summaryrefslogtreecommitdiff
path: root/libjava/classpath/gnu
diff options
context:
space:
mode:
Diffstat (limited to 'libjava/classpath/gnu')
-rw-r--r--libjava/classpath/gnu/CORBA/Asynchron.java185
-rw-r--r--libjava/classpath/gnu/CORBA/BigDecimalHelper.java191
-rw-r--r--libjava/classpath/gnu/CORBA/ByteArrayComparator.java90
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/AbstractCdrInput.java1768
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/AbstractCdrOutput.java1047
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/AbstractDataInput.java392
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/AbstractDataOutput.java185
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/AligningInput.java131
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/AligningOutput.java148
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/ArrayValueHelper.java254
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/BigEndianInputStream.java61
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/BigEndianOutputStream.java62
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/BufferedCdrOutput.java156
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/BufferredCdrInput.java153
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/EncapsulationStream.java147
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/HeadlessInput.java749
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/IDLTypeHelper.java169
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/LittleEndianInputStream.java634
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/LittleEndianOutputStream.java253
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/UnknownExceptionCtxHandler.java292
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/VMVio.java101
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/Vio.java1474
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/gnuRuntime.java338
-rw-r--r--libjava/classpath/gnu/CORBA/CDR/gnuValueStream.java71
-rw-r--r--libjava/classpath/gnu/CORBA/CdrEncapsCodecImpl.java358
-rw-r--r--libjava/classpath/gnu/CORBA/CollocatedOrbs.java160
-rw-r--r--libjava/classpath/gnu/CORBA/Connected_objects.java255
-rw-r--r--libjava/classpath/gnu/CORBA/CorbaList.java115
-rw-r--r--libjava/classpath/gnu/CORBA/DefaultSocketFactory.java79
-rw-r--r--libjava/classpath/gnu/CORBA/DefinitionKindHolder.java91
-rw-r--r--libjava/classpath/gnu/CORBA/DuplicateNameHolder.java106
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/AbstractAny.java177
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/DivideableAny.java512
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/NameValuePairHolder.java94
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/RecordAny.java405
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/UndivideableAny.java493
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/ValueChangeListener.java50
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/gnuDynAny.java945
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/gnuDynAnyFactory.java356
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/gnuDynArray.java337
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/gnuDynEnum.java244
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/gnuDynFixed.java252
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/gnuDynSequence.java254
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/gnuDynStruct.java109
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/gnuDynUnion.java437
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/gnuDynValue.java380
-rw-r--r--libjava/classpath/gnu/CORBA/DynAn/gnuDynValueBox.java389
-rw-r--r--libjava/classpath/gnu/CORBA/DynAnySeqHolder.java116
-rw-r--r--libjava/classpath/gnu/CORBA/EmptyExceptionHolder.java131
-rw-r--r--libjava/classpath/gnu/CORBA/ForwardRequestHelper.java152
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/CancelHeader.java70
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/CharSets_OSF.java238
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/CloseMessage.java106
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/CodeSetServiceContext.java222
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/ContextHandler.java76
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/ErrorMessage.java114
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/MessageHeader.java465
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/ReplyHeader.java145
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/RequestHeader.java156
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/ServiceContext.java301
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/v1_0/CancelHeader.java72
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/v1_0/ReplyHeader.java141
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/v1_0/RequestHeader.java159
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/v1_2/ReplyHeader.java118
-rw-r--r--libjava/classpath/gnu/CORBA/GIOP/v1_2/RequestHeader.java222
-rw-r--r--libjava/classpath/gnu/CORBA/GeneralHolder.java178
-rw-r--r--libjava/classpath/gnu/CORBA/HolderLocator.java184
-rw-r--r--libjava/classpath/gnu/CORBA/IOR.java824
-rw-r--r--libjava/classpath/gnu/CORBA/Interceptor/ClientRequestInterceptors.java139
-rw-r--r--libjava/classpath/gnu/CORBA/Interceptor/ForwardRequestHolder.java106
-rw-r--r--libjava/classpath/gnu/CORBA/Interceptor/IORInterceptors.java189
-rw-r--r--libjava/classpath/gnu/CORBA/Interceptor/Registrator.java472
-rw-r--r--libjava/classpath/gnu/CORBA/Interceptor/ServerRequestInterceptors.java139
-rw-r--r--libjava/classpath/gnu/CORBA/Interceptor/gnuClientRequestInfo.java337
-rw-r--r--libjava/classpath/gnu/CORBA/Interceptor/gnuIcCurrent.java255
-rw-r--r--libjava/classpath/gnu/CORBA/Interceptor/gnuIorInfo.java156
-rw-r--r--libjava/classpath/gnu/CORBA/Interceptor/gnuServerRequestInfo.java476
-rw-r--r--libjava/classpath/gnu/CORBA/IorDelegate.java425
-rw-r--r--libjava/classpath/gnu/CORBA/IorObject.java118
-rw-r--r--libjava/classpath/gnu/CORBA/IorProvider.java52
-rw-r--r--libjava/classpath/gnu/CORBA/Minor.java282
-rw-r--r--libjava/classpath/gnu/CORBA/NameDynAnyPairHolder.java115
-rw-r--r--libjava/classpath/gnu/CORBA/NameDynAnyPairSeqHolder.java115
-rw-r--r--libjava/classpath/gnu/CORBA/NameValuePairHolder.java105
-rw-r--r--libjava/classpath/gnu/CORBA/NameValuePairSeqHolder.java105
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/Binding_iterator_impl.java141
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/Ext.java232
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/NameComponentComparator.java98
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/NameParser.java527
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/NameTransformer.java326
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/NameValidator.java79
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/NamingMap.java190
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/NamingServiceTransient.java146
-rw-r--r--libjava/classpath/gnu/CORBA/NamingService/TransientContext.java443
-rw-r--r--libjava/classpath/gnu/CORBA/ObjectCreator.java590
-rw-r--r--libjava/classpath/gnu/CORBA/OctetHolder.java129
-rw-r--r--libjava/classpath/gnu/CORBA/OrbFocused.java375
-rw-r--r--libjava/classpath/gnu/CORBA/OrbFunctional.java1794
-rw-r--r--libjava/classpath/gnu/CORBA/OrbRestricted.java583
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/AOM.java406
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/AccessiblePolicy.java62
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/DynamicImpHandler.java85
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/ForwardRequestHolder.java107
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/ForwardedServant.java209
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/InvalidPolicyHolder.java106
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/LocalDelegate.java385
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/LocalRequest.java687
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/LocalServerRequest.java199
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/ORB_1_4.java293
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/ServantDelegateImpl.java232
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/StandardPolicies.java128
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuAdapterActivator.java81
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuForwardRequest.java90
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuIdAssignmentPolicy.java80
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuIdUniquenessPolicy.java80
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuImplicitActivationPolicy.java80
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuLifespanPolicy.java80
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuPOA.java1817
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuPOAManager.java272
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuPoaCurrent.java179
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuRequestProcessingPolicy.java80
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuServantObject.java825
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuServantRetentionPolicy.java80
-rw-r--r--libjava/classpath/gnu/CORBA/Poa/gnuThreadPolicy.java80
-rw-r--r--libjava/classpath/gnu/CORBA/RawReply.java95
-rw-r--r--libjava/classpath/gnu/CORBA/ResponseHandlerImpl.java189
-rw-r--r--libjava/classpath/gnu/CORBA/SafeForDirectCalls.java50
-rw-r--r--libjava/classpath/gnu/CORBA/ServiceDetailHolder.java91
-rw-r--r--libjava/classpath/gnu/CORBA/ServiceRequestAdapter.java167
-rw-r--r--libjava/classpath/gnu/CORBA/SetOverrideTypeHolder.java90
-rw-r--r--libjava/classpath/gnu/CORBA/SimpleDelegate.java318
-rw-r--r--libjava/classpath/gnu/CORBA/SocketRepository.java148
-rw-r--r--libjava/classpath/gnu/CORBA/StreamBasedRequest.java60
-rw-r--r--libjava/classpath/gnu/CORBA/StreamHolder.java123
-rw-r--r--libjava/classpath/gnu/CORBA/StubLocator.java110
-rw-r--r--libjava/classpath/gnu/CORBA/TypeCodeHelper.java304
-rw-r--r--libjava/classpath/gnu/CORBA/TypeKindNamer.java183
-rw-r--r--libjava/classpath/gnu/CORBA/Unexpected.java128
-rw-r--r--libjava/classpath/gnu/CORBA/Version.java222
-rw-r--r--libjava/classpath/gnu/CORBA/WCharHolder.java128
-rw-r--r--libjava/classpath/gnu/CORBA/WStringHolder.java131
-rw-r--r--libjava/classpath/gnu/CORBA/_PolicyImplBase.java232
-rw-r--r--libjava/classpath/gnu/CORBA/gnuAny.java907
-rw-r--r--libjava/classpath/gnu/CORBA/gnuCodecFactory.java90
-rw-r--r--libjava/classpath/gnu/CORBA/gnuContext.java202
-rw-r--r--libjava/classpath/gnu/CORBA/gnuContextList.java81
-rw-r--r--libjava/classpath/gnu/CORBA/gnuEnvironment.java72
-rw-r--r--libjava/classpath/gnu/CORBA/gnuExceptionList.java82
-rw-r--r--libjava/classpath/gnu/CORBA/gnuNVList.java127
-rw-r--r--libjava/classpath/gnu/CORBA/gnuNamedValue.java112
-rw-r--r--libjava/classpath/gnu/CORBA/gnuRequest.java1423
-rw-r--r--libjava/classpath/gnu/CORBA/gnuValueHolder.java135
-rw-r--r--libjava/classpath/gnu/CORBA/interfaces/SocketFactory.java95
-rw-r--r--libjava/classpath/gnu/CORBA/interfaces/package.html49
-rw-r--r--libjava/classpath/gnu/CORBA/typecodes/AliasTypeCode.java148
-rw-r--r--libjava/classpath/gnu/CORBA/typecodes/ArrayTypeCode.java272
-rw-r--r--libjava/classpath/gnu/CORBA/typecodes/FixedTypeCode.java152
-rw-r--r--libjava/classpath/gnu/CORBA/typecodes/GeneralTypeCode.java249
-rw-r--r--libjava/classpath/gnu/CORBA/typecodes/PrimitiveTypeCode.java201
-rw-r--r--libjava/classpath/gnu/CORBA/typecodes/RecordTypeCode.java252
-rw-r--r--libjava/classpath/gnu/CORBA/typecodes/RecursiveTypeCode.java84
-rw-r--r--libjava/classpath/gnu/CORBA/typecodes/StringTypeCode.java89
-rw-r--r--libjava/classpath/gnu/CORBA/typecodes/package.html48
-rw-r--r--libjava/classpath/gnu/classpath/.cvsignore1
-rw-r--r--libjava/classpath/gnu/classpath/Configuration.java.in114
-rw-r--r--libjava/classpath/gnu/classpath/NotImplementedException.java61
-rw-r--r--libjava/classpath/gnu/classpath/Pair.java126
-rw-r--r--libjava/classpath/gnu/classpath/Pointer.java47
-rw-r--r--libjava/classpath/gnu/classpath/Pointer32.java52
-rw-r--r--libjava/classpath/gnu/classpath/Pointer64.java52
-rw-r--r--libjava/classpath/gnu/classpath/ServiceFactory.java653
-rw-r--r--libjava/classpath/gnu/classpath/ServiceProviderLoadingAction.java149
-rw-r--r--libjava/classpath/gnu/classpath/SystemProperties.java173
-rw-r--r--libjava/classpath/gnu/classpath/debug/Component.java175
-rw-r--r--libjava/classpath/gnu/classpath/debug/PreciseFilter.java105
-rw-r--r--libjava/classpath/gnu/classpath/debug/Simple1LineFormatter.java161
-rw-r--r--libjava/classpath/gnu/classpath/debug/SystemLogger.java102
-rw-r--r--libjava/classpath/gnu/classpath/debug/TeeInputStream.java98
-rw-r--r--libjava/classpath/gnu/classpath/debug/TeeOutputStream.java93
-rw-r--r--libjava/classpath/gnu/classpath/debug/TeeReader.java98
-rw-r--r--libjava/classpath/gnu/classpath/debug/TeeWriter.java93
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/Jdwp.java416
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/JdwpConstants.java901
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/BreakpointEvent.java117
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/ClassPrepareEvent.java147
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/ClassUnloadEvent.java96
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/Event.java180
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/EventManager.java305
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/EventRequest.java383
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/ExceptionEvent.java157
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/MethodEntryEvent.java118
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/MethodExitEvent.java115
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/SingleStepEvent.java121
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/ThreadEndEvent.java104
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/ThreadStartEvent.java109
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/VmDeathEvent.java83
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/VmInitEvent.java94
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/filters/ClassExcludeFilter.java75
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/filters/ClassMatchFilter.java112
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/filters/ClassOnlyFilter.java109
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/filters/ConditionalFilter.java82
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/filters/CountFilter.java95
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/filters/ExceptionOnlyFilter.java123
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/filters/FieldOnlyFilter.java112
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/filters/IEventFilter.java65
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/filters/InstanceOnlyFilter.java101
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/filters/LocationOnlyFilter.java94
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/filters/StepFilter.java126
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/event/filters/ThreadOnlyFilter.java101
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/AbsentInformationException.java56
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidClassException.java63
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidClassLoaderException.java62
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidCountException.java61
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidEventTypeException.java63
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidFieldException.java63
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidFrameException.java63
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidLocationException.java62
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidMethodException.java63
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidObjectException.java63
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidSlotException.java62
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidStringException.java68
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidTagException.java57
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadException.java63
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/InvalidThreadGroupException.java63
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/JdwpException.java86
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/JdwpIllegalArgumentException.java62
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/JdwpInternalErrorException.java62
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/NativeMethodException.java63
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/NotImplementedException.java58
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/TypeMismatchException.java62
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/exception/VmDeadException.java55
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/id/ArrayId.java62
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/id/ArrayReferenceTypeId.java59
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/id/ClassLoaderId.java82
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/id/ClassObjectId.java82
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/id/ClassReferenceTypeId.java59
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/id/InterfaceReferenceTypeId.java59
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/id/JdwpId.java151
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/id/NullObjectId.java79
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/id/ObjectId.java131
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/id/ReferenceTypeId.java91
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/id/StringId.java82
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/id/ThreadGroupId.java82
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/id/ThreadId.java85
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/ArrayReferenceCommandSet.java176
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/ArrayTypeCommandSet.java105
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/ClassLoaderReferenceCommandSet.java108
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/ClassObjectReferenceCommandSet.java97
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/ClassTypeCommandSet.java205
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/CommandSet.java74
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/EventRequestCommandSet.java220
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/FieldCommandSet.java67
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/InterfaceTypeCommandSet.java68
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/MethodCommandSet.java157
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/ObjectReferenceCommandSet.java255
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/PacketProcessor.java221
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/ReferenceTypeCommandSet.java341
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/StackFrameCommandSet.java170
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/StringReferenceCommandSet.java99
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/ThreadGroupReferenceCommandSet.java179
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/ThreadReferenceCommandSet.java265
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/processor/VirtualMachineCommandSet.java472
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/transport/ITransport.java88
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/transport/JdwpCommandPacket.java149
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/transport/JdwpConnection.java307
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/transport/JdwpPacket.java277
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/transport/JdwpReplyPacket.java137
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/transport/SocketTransport.java196
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/transport/TransportException.java75
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/transport/TransportFactory.java115
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/util/JdwpString.java95
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/util/LineTable.java95
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/util/Location.java168
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/util/MethodResult.java86
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/util/MonitorInfo.java76
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/util/NullObject.java50
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/util/Signature.java151
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/util/VariableTable.java110
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/ArrayValue.java92
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/BooleanValue.java99
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/ByteValue.java99
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/CharValue.java99
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/DoubleValue.java99
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/FloatValue.java99
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/IntValue.java99
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/LongValue.java99
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/ObjectValue.java102
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/ShortValue.java99
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/StringValue.java103
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/Value.java155
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/ValueFactory.java247
-rw-r--r--libjava/classpath/gnu/classpath/jdwp/value/VoidValue.java82
-rw-r--r--libjava/classpath/gnu/classpath/toolkit/DefaultDaemonThreadFactory.java59
-rw-r--r--libjava/classpath/gnu/java/awt/AWTUtilities.java898
-rw-r--r--libjava/classpath/gnu/java/awt/BitMaskExtent.java79
-rw-r--r--libjava/classpath/gnu/java/awt/BitwiseXORComposite.java295
-rw-r--r--libjava/classpath/gnu/java/awt/Buffers.java225
-rw-r--r--libjava/classpath/gnu/java/awt/ClasspathGraphicsEnvironment.java67
-rw-r--r--libjava/classpath/gnu/java/awt/ClasspathToolkit.java231
-rw-r--r--libjava/classpath/gnu/java/awt/ComponentDataBlitOp.java156
-rw-r--r--libjava/classpath/gnu/java/awt/ComponentReshapeEvent.java85
-rw-r--r--libjava/classpath/gnu/java/awt/EmbeddedWindow.java138
-rw-r--r--libjava/classpath/gnu/java/awt/EventModifier.java107
-rw-r--r--libjava/classpath/gnu/java/awt/GradientPaintContext.java164
-rw-r--r--libjava/classpath/gnu/java/awt/LowPriorityEvent.java48
-rw-r--r--libjava/classpath/gnu/java/awt/color/CieXyzConverter.java73
-rw-r--r--libjava/classpath/gnu/java/awt/color/ClutProfileConverter.java152
-rw-r--r--libjava/classpath/gnu/java/awt/color/ColorLookUpTable.java429
-rw-r--r--libjava/classpath/gnu/java/awt/color/ColorSpaceConverter.java69
-rw-r--r--libjava/classpath/gnu/java/awt/color/GrayProfileConverter.java137
-rw-r--r--libjava/classpath/gnu/java/awt/color/GrayScaleConverter.java110
-rw-r--r--libjava/classpath/gnu/java/awt/color/LinearRGBConverter.java152
-rw-r--r--libjava/classpath/gnu/java/awt/color/ProfileHeader.java398
-rw-r--r--libjava/classpath/gnu/java/awt/color/PyccConverter.java71
-rw-r--r--libjava/classpath/gnu/java/awt/color/RgbProfileConverter.java244
-rw-r--r--libjava/classpath/gnu/java/awt/color/SrgbConverter.java152
-rw-r--r--libjava/classpath/gnu/java/awt/color/TagEntry.java121
-rw-r--r--libjava/classpath/gnu/java/awt/color/ToneReproductionCurve.java177
-rw-r--r--libjava/classpath/gnu/java/awt/color/package.html46
-rw-r--r--libjava/classpath/gnu/java/awt/dnd/GtkMouseDragGestureRecognizer.java172
-rw-r--r--libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java184
-rw-r--r--libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java125
-rw-r--r--libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetPeer.java68
-rw-r--r--libjava/classpath/gnu/java/awt/doc-files/BitwiseXORComposite-1.pngbin0 -> 8845 bytes
-rw-r--r--libjava/classpath/gnu/java/awt/font/FontDelegate.java329
-rw-r--r--libjava/classpath/gnu/java/awt/font/FontFactory.java90
-rw-r--r--libjava/classpath/gnu/java/awt/font/GNUGlyphVector.java663
-rw-r--r--libjava/classpath/gnu/java/awt/font/OpenTypeFontPeer.java565
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/AutoHinter.java83
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/AxisHints.java112
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/Constants.java86
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/Edge.java82
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/GlyphHints.java640
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/HintScaler.java53
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/Latin.java1363
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/LatinAxis.java62
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/LatinBlue.java61
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/LatinMetrics.java66
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/Script.java62
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/ScriptMetrics.java53
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/Segment.java97
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/Utils.java255
-rw-r--r--libjava/classpath/gnu/java/awt/font/autofit/Width.java64
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/CharGlyphMap.java1027
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/GlyphNamer.java1135
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/Hinter.java63
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/MacResourceFork.java235
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/NameDecoder.java702
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java882
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFontFactory.java140
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/Scaler.java205
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/truetype/Fixed.java176
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java447
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLocator.java187
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphMeasurer.java228
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/truetype/Point.java287
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java380
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/truetype/VirtualMachine.java1815
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java291
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/truetype/ZonePathIterator.java393
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/truetype/doc-files/ZonePathIterator-1.diabin0 -> 1572 bytes
-rw-r--r--libjava/classpath/gnu/java/awt/font/opentype/truetype/doc-files/ZonePathIterator-1.pngbin0 -> 11278 bytes
-rw-r--r--libjava/classpath/gnu/java/awt/image/AsyncImage.java300
-rw-r--r--libjava/classpath/gnu/java/awt/image/ImageConverter.java528
-rw-r--r--libjava/classpath/gnu/java/awt/image/ImageDecoder.java188
-rw-r--r--libjava/classpath/gnu/java/awt/image/XBMDecoder.java155
-rw-r--r--libjava/classpath/gnu/java/awt/image/package.html46
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java2094
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/ActiveEdges.java197
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/AlphaCompositeContext.java316
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/CubicSegment.java184
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/ImagePaint.java192
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/LineSegment.java118
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/PixelCoverage.java132
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/Pixelizer.java56
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/PolyEdge.java171
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/PolyEdgeComparator.java70
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/QuadSegment.java260
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/RasterGraphics.java118
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/Scanline.java91
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java451
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/ScanlineCoverage.java630
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/Segment.java158
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/ShapeCache.java90
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/ShapeWrapper.java119
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/TextCacheKey.java153
-rw-r--r--libjava/classpath/gnu/java/awt/java2d/TexturePaintContext.java211
-rw-r--r--libjava/classpath/gnu/java/awt/package.html46
-rw-r--r--libjava/classpath/gnu/java/awt/peer/ClasspathDesktopPeer.java301
-rw-r--r--libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java865
-rw-r--r--libjava/classpath/gnu/java/awt/peer/EmbeddedWindowPeer.java47
-rw-r--r--libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java461
-rw-r--r--libjava/classpath/gnu/java/awt/peer/GnomeDesktopPeer.java155
-rw-r--r--libjava/classpath/gnu/java/awt/peer/KDEDesktopPeer.java135
-rw-r--r--libjava/classpath/gnu/java/awt/peer/NativeEventLoopRunningEvent.java58
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java283
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java538
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java2176
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java428
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java355
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java941
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphicsCopy.java122
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java630
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java545
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java156
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java172
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java785
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GdkRobotPeer.java99
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java362
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkButtonPeer.java93
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkCanvasPeer.java60
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java74
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java255
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java142
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java436
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java129
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java920
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java138
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkCursor.java72
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkDialogPeer.java63
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkEmbeddedWindowPeer.java73
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java229
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java254
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkGenericPeer.java145
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java541
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java169
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java102
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java187
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java188
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java113
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java104
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java116
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java126
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java65
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkPanelPeer.java67
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java68
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java111
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java92
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java675
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java223
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java200
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java766
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java207
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java437
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java325
-rw-r--r--libjava/classpath/gnu/java/awt/peer/gtk/package.html46
-rw-r--r--libjava/classpath/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java118
-rw-r--r--libjava/classpath/gnu/java/awt/peer/headless/HeadlessToolkit.java385
-rw-r--r--libjava/classpath/gnu/java/awt/peer/package.html46
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/MainQtThread.java84
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/NativeWrapper.java43
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QMatrix.java72
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QPainterPath.java140
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QPen.java70
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtAudioClip.java110
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtButtonPeer.java75
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtCanvasPeer.java65
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtCheckboxPeer.java111
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtChoicePeer.java93
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtComponentGraphics.java120
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtComponentPeer.java834
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtContainerPeer.java112
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtDialogPeer.java73
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtEmbeddedWindowPeer.java64
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtFileDialogPeer.java83
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtFontMetrics.java125
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtFontPeer.java197
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtFramePeer.java164
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtGraphics.java714
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtGraphicsEnvironment.java105
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtImage.java641
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtImageConsumer.java147
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtImageDirectGraphics.java145
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtImageGraphics.java139
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtLabelPeer.java62
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtListPeer.java188
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtMenuBarPeer.java101
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtMenuComponentPeer.java94
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtMenuItemPeer.java100
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtMenuPeer.java149
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtPanelPeer.java56
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtPopupMenuPeer.java76
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtRepaintThread.java156
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtScreenDevice.java115
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtScreenDeviceConfiguration.java145
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtScrollPanePeer.java90
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtScrollbarPeer.java80
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtTextAreaPeer.java179
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtTextFieldPeer.java159
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtToolkit.java470
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtVolatileImage.java434
-rw-r--r--libjava/classpath/gnu/java/awt/peer/qt/QtWindowPeer.java105
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingButtonPeer.java261
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingCanvasPeer.java64
-rwxr-xr-xlibjava/classpath/gnu/java/awt/peer/swing/SwingCheckboxPeer.java256
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java99
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java1136
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java378
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java197
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingLabelPeer.java242
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingListPeer.java364
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java295
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingMenuItemPeer.java157
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingMenuPeer.java284
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingPanelPeer.java67
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingTextAreaPeer.java487
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java411
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingToolkit.java181
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java99
-rw-r--r--libjava/classpath/gnu/java/awt/peer/swing/package.html71
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/GLGraphics.java134
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/KeyboardMapping.java419
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/PixmapVolatileImage.java185
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/XDialogPeer.java61
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/XEventPump.java486
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/XFontPeer.java770
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/XFramePeer.java145
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/XGraphics2D.java508
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/XGraphicsConfiguration.java200
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/XGraphicsDevice.java200
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/XGraphicsEnvironment.java203
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/XImage.java178
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/XToolkit.java667
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/XWindowPeer.java303
-rw-r--r--libjava/classpath/gnu/java/awt/peer/x/ZPixmapDataBuffer.java67
-rw-r--r--libjava/classpath/gnu/java/awt/print/JavaPrinterGraphics.java518
-rw-r--r--libjava/classpath/gnu/java/awt/print/JavaPrinterJob.java403
-rw-r--r--libjava/classpath/gnu/java/awt/print/PostScriptGraphics2D.java1349
-rw-r--r--libjava/classpath/gnu/java/awt/print/SpooledDocument.java90
-rw-r--r--libjava/classpath/gnu/java/beans/BeanInfoEmbryo.java171
-rw-r--r--libjava/classpath/gnu/java/beans/DefaultExceptionListener.java66
-rw-r--r--libjava/classpath/gnu/java/beans/DummyAppletContext.java165
-rw-r--r--libjava/classpath/gnu/java/beans/DummyAppletStub.java115
-rw-r--r--libjava/classpath/gnu/java/beans/ExplicitBeanInfo.java149
-rw-r--r--libjava/classpath/gnu/java/beans/IntrospectionIncubator.java441
-rw-r--r--libjava/classpath/gnu/java/beans/TODO1
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/AbstractContext.java70
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/AbstractCreatableObjectContext.java113
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/AbstractElementHandler.java316
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/AbstractObjectContext.java127
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/ArrayContext.java122
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/ArrayHandler.java118
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/AssemblyException.java57
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/BooleanHandler.java67
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/ByteHandler.java59
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/CharHandler.java62
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/ClassHandler.java66
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/ConstructorContext.java102
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/Context.java137
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/DecoderContext.java124
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/DoubleHandler.java59
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/DummyContext.java116
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/DummyHandler.java156
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/ElementHandler.java130
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/FloatHandler.java59
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/GrowableArrayContext.java138
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/IndexContext.java130
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/IntHandler.java59
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/JavaHandler.java93
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/LongHandler.java59
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/MethodContext.java107
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/MethodFinder.java177
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/NullHandler.java62
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/ObjectContext.java100
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/ObjectHandler.java169
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/PersistenceParser.java485
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/PropertyContext.java137
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/ShortHandler.java58
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/SimpleHandler.java111
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/StaticMethodContext.java95
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/StringHandler.java54
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/VoidHandler.java140
-rw-r--r--libjava/classpath/gnu/java/beans/decoder/package.html46
-rw-r--r--libjava/classpath/gnu/java/beans/editors/ColorEditor.java100
-rw-r--r--libjava/classpath/gnu/java/beans/editors/FontEditor.java77
-rw-r--r--libjava/classpath/gnu/java/beans/editors/NativeBooleanEditor.java76
-rw-r--r--libjava/classpath/gnu/java/beans/editors/NativeByteEditor.java61
-rw-r--r--libjava/classpath/gnu/java/beans/editors/NativeDoubleEditor.java61
-rw-r--r--libjava/classpath/gnu/java/beans/editors/NativeFloatEditor.java61
-rw-r--r--libjava/classpath/gnu/java/beans/editors/NativeIntEditor.java61
-rw-r--r--libjava/classpath/gnu/java/beans/editors/NativeLongEditor.java61
-rw-r--r--libjava/classpath/gnu/java/beans/editors/NativeShortEditor.java61
-rw-r--r--libjava/classpath/gnu/java/beans/editors/StringEditor.java61
-rw-r--r--libjava/classpath/gnu/java/beans/editors/TODO4
-rw-r--r--libjava/classpath/gnu/java/beans/editors/package.html46
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/ArrayPersistenceDelegate.java153
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/ClassPersistenceDelegate.java80
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/CollectionPersistenceDelegate.java84
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/Context.java88
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/GenericScannerState.java257
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/IgnoringScannerState.java133
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/MapPersistenceDelegate.java81
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/ObjectId.java132
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/PrimitivePersistenceDelegate.java74
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/ReportingScannerState.java131
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/Root.java198
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/ScanEngine.java860
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/ScannerState.java236
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/StAXWriter.java233
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/Writer.java174
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/ArrayInstantiation.java74
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/Array_Get.java62
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/Array_Set.java57
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/ClassResolution.java67
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/Element.java157
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/List_Get.java56
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/List_Set.java56
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/MethodInvocation.java62
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/NullObject.java61
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/ObjectInstantiation.java68
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/ObjectReference.java68
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/PrimitiveInstantiation.java69
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/StaticFieldAccess.java66
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/StaticMethodInvocation.java67
-rw-r--r--libjava/classpath/gnu/java/beans/encoder/elements/StringReference.java63
-rw-r--r--libjava/classpath/gnu/java/beans/package.html46
-rw-r--r--libjava/classpath/gnu/java/io/ASN1ParsingException.java56
-rw-r--r--libjava/classpath/gnu/java/io/Base64InputStream.java220
-rw-r--r--libjava/classpath/gnu/java/io/ClassLoaderObjectInputStream.java73
-rw-r--r--libjava/classpath/gnu/java/io/NullOutputStream.java56
-rw-r--r--libjava/classpath/gnu/java/io/ObjectIdentityMap2Int.java292
-rw-r--r--libjava/classpath/gnu/java/io/ObjectIdentityWrapper.java100
-rw-r--r--libjava/classpath/gnu/java/io/PlatformHelper.java129
-rw-r--r--libjava/classpath/gnu/java/io/package.html46
-rw-r--r--libjava/classpath/gnu/java/lang/ArrayHelper.java78
-rw-r--r--libjava/classpath/gnu/java/lang/CPStringBuilder.java1161
-rw-r--r--libjava/classpath/gnu/java/lang/CharData.java1705
-rw-r--r--libjava/classpath/gnu/java/lang/ClassHelper.java205
-rw-r--r--libjava/classpath/gnu/java/lang/InstrumentationImpl.java241
-rw-r--r--libjava/classpath/gnu/java/lang/MainThread.java83
-rw-r--r--libjava/classpath/gnu/java/lang/management/BeanImpl.java447
-rw-r--r--libjava/classpath/gnu/java/lang/management/ClassLoadingMXBeanImpl.java98
-rw-r--r--libjava/classpath/gnu/java/lang/management/CompilationMXBeanImpl.java105
-rw-r--r--libjava/classpath/gnu/java/lang/management/GarbageCollectorMXBeanImpl.java84
-rw-r--r--libjava/classpath/gnu/java/lang/management/MemoryMXBeanImpl.java281
-rw-r--r--libjava/classpath/gnu/java/lang/management/MemoryManagerMXBeanImpl.java112
-rw-r--r--libjava/classpath/gnu/java/lang/management/MemoryPoolMXBeanImpl.java226
-rw-r--r--libjava/classpath/gnu/java/lang/management/OperatingSystemMXBeanImpl.java95
-rw-r--r--libjava/classpath/gnu/java/lang/management/RuntimeMXBeanImpl.java197
-rw-r--r--libjava/classpath/gnu/java/lang/management/ThreadMXBeanImpl.java350
-rw-r--r--libjava/classpath/gnu/java/lang/management/package.html46
-rw-r--r--libjava/classpath/gnu/java/lang/package.html46
-rw-r--r--libjava/classpath/gnu/java/lang/reflect/ClassSignatureParser.java92
-rw-r--r--libjava/classpath/gnu/java/lang/reflect/FieldSignatureParser.java103
-rw-r--r--libjava/classpath/gnu/java/lang/reflect/GenericSignatureParser.java631
-rw-r--r--libjava/classpath/gnu/java/lang/reflect/MethodSignatureParser.java167
-rw-r--r--libjava/classpath/gnu/java/lang/reflect/TypeImpl.java63
-rw-r--r--libjava/classpath/gnu/java/lang/reflect/TypeSignature.java290
-rw-r--r--libjava/classpath/gnu/java/lang/reflect/package.html46
-rw-r--r--libjava/classpath/gnu/java/locale/.cvsignore1
-rw-r--r--libjava/classpath/gnu/java/locale/LocaleHelper.java147
-rw-r--r--libjava/classpath/gnu/java/locale/package.html46
-rw-r--r--libjava/classpath/gnu/java/math/Fixed.java220
-rw-r--r--libjava/classpath/gnu/java/math/GMP.java474
-rw-r--r--libjava/classpath/gnu/java/math/MPN.java771
-rw-r--r--libjava/classpath/gnu/java/math/package.html46
-rw-r--r--libjava/classpath/gnu/java/net/CRLFInputStream.java178
-rw-r--r--libjava/classpath/gnu/java/net/CRLFOutputStream.java182
-rw-r--r--libjava/classpath/gnu/java/net/DefaultContentHandlerFactory.java94
-rw-r--r--libjava/classpath/gnu/java/net/DefaultProxySelector.java80
-rw-r--r--libjava/classpath/gnu/java/net/EmptyX509TrustManager.java69
-rw-r--r--libjava/classpath/gnu/java/net/GetLocalHostAction.java64
-rw-r--r--libjava/classpath/gnu/java/net/HeaderFieldHelper.java136
-rw-r--r--libjava/classpath/gnu/java/net/IndexListParser.java183
-rw-r--r--libjava/classpath/gnu/java/net/LineInputStream.java223
-rw-r--r--libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java486
-rw-r--r--libjava/classpath/gnu/java/net/PlainSocketImpl.java678
-rw-r--r--libjava/classpath/gnu/java/net/URLParseError.java57
-rw-r--r--libjava/classpath/gnu/java/net/loader/FileResource.java82
-rw-r--r--libjava/classpath/gnu/java/net/loader/FileURLLoader.java145
-rw-r--r--libjava/classpath/gnu/java/net/loader/JarURLLoader.java215
-rw-r--r--libjava/classpath/gnu/java/net/loader/JarURLResource.java94
-rw-r--r--libjava/classpath/gnu/java/net/loader/RemoteResource.java78
-rw-r--r--libjava/classpath/gnu/java/net/loader/RemoteURLLoader.java101
-rw-r--r--libjava/classpath/gnu/java/net/loader/Resource.java110
-rw-r--r--libjava/classpath/gnu/java/net/loader/URLLoader.java148
-rw-r--r--libjava/classpath/gnu/java/net/loader/URLStreamHandlerCache.java85
-rw-r--r--libjava/classpath/gnu/java/net/local/LocalServerSocket.java171
-rw-r--r--libjava/classpath/gnu/java/net/local/LocalSocket.java312
-rw-r--r--libjava/classpath/gnu/java/net/local/LocalSocketAddress.java100
-rw-r--r--libjava/classpath/gnu/java/net/local/LocalSocketImpl.java334
-rw-r--r--libjava/classpath/gnu/java/net/package.html46
-rw-r--r--libjava/classpath/gnu/java/net/protocol/file/Connection.java376
-rw-r--r--libjava/classpath/gnu/java/net/protocol/file/Handler.java91
-rw-r--r--libjava/classpath/gnu/java/net/protocol/file/package.html46
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/ActiveModeDTP.java251
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/BlockInputStream.java149
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/BlockOutputStream.java110
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/CompressedInputStream.java214
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/CompressedOutputStream.java227
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/DTP.java91
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/DTPInputStream.java87
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/DTPOutputStream.java85
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java1352
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java75
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java111
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java375
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/Handler.java69
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java200
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java94
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java84
-rw-r--r--libjava/classpath/gnu/java/net/protocol/ftp/package.html60
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Authenticator.java58
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/ByteArrayRequestBodyWriter.java106
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/ChunkedInputStream.java223
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Cookie.java161
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/CookieManager.java65
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Credentials.java87
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java897
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/HTTPDateFormat.java440
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java693
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Handler.java72
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Headers.java424
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/LimitedLengthInputStream.java216
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Request.java857
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/RequestBodyWriter.java68
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/Response.java223
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/ResponseHeaderHandler.java56
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java137
-rw-r--r--libjava/classpath/gnu/java/net/protocol/http/package.html76
-rw-r--r--libjava/classpath/gnu/java/net/protocol/https/Handler.java75
-rw-r--r--libjava/classpath/gnu/java/net/protocol/jar/Connection.java232
-rw-r--r--libjava/classpath/gnu/java/net/protocol/jar/Handler.java217
-rw-r--r--libjava/classpath/gnu/java/net/protocol/jar/package.html46
-rw-r--r--libjava/classpath/gnu/java/nio/ChannelInputStream.java89
-rw-r--r--libjava/classpath/gnu/java/nio/ChannelOutputStream.java67
-rw-r--r--libjava/classpath/gnu/java/nio/ChannelReader.java217
-rw-r--r--libjava/classpath/gnu/java/nio/ChannelWriter.java190
-rw-r--r--libjava/classpath/gnu/java/nio/DatagramChannelImpl.java240
-rw-r--r--libjava/classpath/gnu/java/nio/DatagramChannelSelectionKey.java68
-rw-r--r--libjava/classpath/gnu/java/nio/EpollSelectionKeyImpl.java122
-rw-r--r--libjava/classpath/gnu/java/nio/EpollSelectorImpl.java399
-rw-r--r--libjava/classpath/gnu/java/nio/FileChannelImpl.java572
-rw-r--r--libjava/classpath/gnu/java/nio/FileLockImpl.java102
-rw-r--r--libjava/classpath/gnu/java/nio/InputStreamChannel.java88
-rw-r--r--libjava/classpath/gnu/java/nio/KqueueSelectionKeyImpl.java187
-rw-r--r--libjava/classpath/gnu/java/nio/KqueueSelectorImpl.java527
-rw-r--r--libjava/classpath/gnu/java/nio/NIOConstants.java47
-rw-r--r--libjava/classpath/gnu/java/nio/NIODatagramSocket.java71
-rw-r--r--libjava/classpath/gnu/java/nio/NIOServerSocket.java106
-rw-r--r--libjava/classpath/gnu/java/nio/NIOSocket.java79
-rw-r--r--libjava/classpath/gnu/java/nio/NIOSocketImpl.java110
-rw-r--r--libjava/classpath/gnu/java/nio/OutputStreamChannel.java87
-rw-r--r--libjava/classpath/gnu/java/nio/PipeImpl.java178
-rw-r--r--libjava/classpath/gnu/java/nio/SelectionKeyImpl.java111
-rw-r--r--libjava/classpath/gnu/java/nio/SelectorImpl.java397
-rw-r--r--libjava/classpath/gnu/java/nio/SelectorProviderImpl.java121
-rw-r--r--libjava/classpath/gnu/java/nio/ServerSocketChannelImpl.java128
-rw-r--r--libjava/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java65
-rw-r--r--libjava/classpath/gnu/java/nio/SocketChannelImpl.java265
-rw-r--r--libjava/classpath/gnu/java/nio/SocketChannelSelectionKey.java65
-rw-r--r--libjava/classpath/gnu/java/nio/SocketChannelSelectionKeyImpl.java78
-rw-r--r--libjava/classpath/gnu/java/nio/VMChannelOwner.java57
-rw-r--r--libjava/classpath/gnu/java/nio/channels/package.html46
-rw-r--r--libjava/classpath/gnu/java/nio/charset/ByteCharset.java193
-rw-r--r--libjava/classpath/gnu/java/nio/charset/ByteDecodeLoopHelper.java164
-rw-r--r--libjava/classpath/gnu/java/nio/charset/ByteEncodeLoopHelper.java165
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp424.java86
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp437.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp737.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp775.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp850.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp852.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp855.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp857.java88
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp860.java88
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp861.java88
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp862.java88
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp863.java88
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp864.java88
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp865.java88
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp866.java88
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp869.java88
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Cp874.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/EncodingHelper.java161
-rw-r--r--libjava/classpath/gnu/java/nio/charset/ISO_8859_1.java165
-rw-r--r--libjava/classpath/gnu/java/nio/charset/ISO_8859_13.java102
-rw-r--r--libjava/classpath/gnu/java/nio/charset/ISO_8859_15.java109
-rw-r--r--libjava/classpath/gnu/java/nio/charset/ISO_8859_2.java108
-rw-r--r--libjava/classpath/gnu/java/nio/charset/ISO_8859_3.java107
-rw-r--r--libjava/classpath/gnu/java/nio/charset/ISO_8859_4.java108
-rw-r--r--libjava/classpath/gnu/java/nio/charset/ISO_8859_5.java106
-rw-r--r--libjava/classpath/gnu/java/nio/charset/ISO_8859_6.java110
-rw-r--r--libjava/classpath/gnu/java/nio/charset/ISO_8859_7.java109
-rw-r--r--libjava/classpath/gnu/java/nio/charset/ISO_8859_8.java108
-rw-r--r--libjava/classpath/gnu/java/nio/charset/ISO_8859_9.java108
-rw-r--r--libjava/classpath/gnu/java/nio/charset/KOI_8.java100
-rw-r--r--libjava/classpath/gnu/java/nio/charset/MS874.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/MacCentralEurope.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/MacCroatian.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/MacCyrillic.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/MacDingbat.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/MacGreek.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/MacIceland.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/MacRoman.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/MacRomania.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/MacSymbol.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/MacThai.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/MacTurkish.java87
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Provider.java271
-rw-r--r--libjava/classpath/gnu/java/nio/charset/US_ASCII.java162
-rw-r--r--libjava/classpath/gnu/java/nio/charset/UTF_16.java80
-rw-r--r--libjava/classpath/gnu/java/nio/charset/UTF_16BE.java84
-rw-r--r--libjava/classpath/gnu/java/nio/charset/UTF_16Decoder.java167
-rw-r--r--libjava/classpath/gnu/java/nio/charset/UTF_16Encoder.java145
-rw-r--r--libjava/classpath/gnu/java/nio/charset/UTF_16LE.java83
-rw-r--r--libjava/classpath/gnu/java/nio/charset/UTF_8.java311
-rw-r--r--libjava/classpath/gnu/java/nio/charset/UnicodeLittle.java74
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Windows1250.java101
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Windows1251.java99
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Windows1252.java98
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Windows1253.java99
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Windows1254.java99
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Windows1255.java99
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Windows1256.java99
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Windows1257.java99
-rw-r--r--libjava/classpath/gnu/java/nio/charset/Windows1258.java99
-rw-r--r--libjava/classpath/gnu/java/nio/charset/iconv/IconvCharset.java85
-rw-r--r--libjava/classpath/gnu/java/nio/charset/iconv/IconvDecoder.java110
-rw-r--r--libjava/classpath/gnu/java/nio/charset/iconv/IconvEncoder.java110
-rw-r--r--libjava/classpath/gnu/java/nio/charset/iconv/IconvMetaData.java450
-rw-r--r--libjava/classpath/gnu/java/nio/charset/iconv/IconvProvider.java110
-rw-r--r--libjava/classpath/gnu/java/nio/charset/package.html46
-rw-r--r--libjava/classpath/gnu/java/nio/package.html46
-rw-r--r--libjava/classpath/gnu/java/rmi/RMIMarshalledObjectInputStream.java71
-rw-r--r--libjava/classpath/gnu/java/rmi/RMIMarshalledObjectOutputStream.java78
-rw-r--r--libjava/classpath/gnu/java/rmi/activation/ActivationSystemTransient.java406
-rw-r--r--libjava/classpath/gnu/java/rmi/activation/BidiTable.java163
-rw-r--r--libjava/classpath/gnu/java/rmi/activation/DefaultActivationGroup.java159
-rw-r--r--libjava/classpath/gnu/java/rmi/activation/DefaultActivationSystem.java118
-rw-r--r--libjava/classpath/gnu/java/rmi/dgc/DGCImpl.java182
-rw-r--r--libjava/classpath/gnu/java/rmi/dgc/DGCImpl_Skel.java144
-rw-r--r--libjava/classpath/gnu/java/rmi/dgc/DGCImpl_Stub.java158
-rw-r--r--libjava/classpath/gnu/java/rmi/dgc/LeaseRenewingTask.java234
-rw-r--r--libjava/classpath/gnu/java/rmi/dgc/package.html46
-rw-r--r--libjava/classpath/gnu/java/rmi/package.html46
-rw-r--r--libjava/classpath/gnu/java/rmi/registry/RegistryImpl.java154
-rw-r--r--libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Skel.java227
-rw-r--r--libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Stub.java293
-rw-r--r--libjava/classpath/gnu/java/rmi/registry/package.html46
-rw-r--r--libjava/classpath/gnu/java/rmi/server/ActivatableRef.java179
-rw-r--r--libjava/classpath/gnu/java/rmi/server/ActivatableServerRef.java227
-rw-r--r--libjava/classpath/gnu/java/rmi/server/CombinedClassLoader.java135
-rw-r--r--libjava/classpath/gnu/java/rmi/server/ConnectionRunnerPool.java156
-rw-r--r--libjava/classpath/gnu/java/rmi/server/ProtocolConstants.java62
-rw-r--r--libjava/classpath/gnu/java/rmi/server/RMIClassLoaderImpl.java357
-rw-r--r--libjava/classpath/gnu/java/rmi/server/RMIDefaultSocketFactory.java59
-rw-r--r--libjava/classpath/gnu/java/rmi/server/RMIHashes.java99
-rw-r--r--libjava/classpath/gnu/java/rmi/server/RMIIncomingThread.java58
-rw-r--r--libjava/classpath/gnu/java/rmi/server/RMIObjectInputStream.java118
-rw-r--r--libjava/classpath/gnu/java/rmi/server/RMIObjectOutputStream.java114
-rw-r--r--libjava/classpath/gnu/java/rmi/server/RMIVoidValue.java51
-rw-r--r--libjava/classpath/gnu/java/rmi/server/UnicastConnection.java231
-rw-r--r--libjava/classpath/gnu/java/rmi/server/UnicastConnectionManager.java468
-rw-r--r--libjava/classpath/gnu/java/rmi/server/UnicastRef.java524
-rw-r--r--libjava/classpath/gnu/java/rmi/server/UnicastRemoteCall.java525
-rw-r--r--libjava/classpath/gnu/java/rmi/server/UnicastRemoteStub.java50
-rw-r--r--libjava/classpath/gnu/java/rmi/server/UnicastServer.java321
-rw-r--r--libjava/classpath/gnu/java/rmi/server/UnicastServerRef.java481
-rw-r--r--libjava/classpath/gnu/java/rmi/server/package.html46
-rw-r--r--libjava/classpath/gnu/java/security/.cvsignore1
-rw-r--r--libjava/classpath/gnu/java/security/Configuration.java.in56
-rw-r--r--libjava/classpath/gnu/java/security/Engine.java282
-rw-r--r--libjava/classpath/gnu/java/security/OID.java512
-rw-r--r--libjava/classpath/gnu/java/security/PolicyFile.java687
-rw-r--r--libjava/classpath/gnu/java/security/Properties.java348
-rw-r--r--libjava/classpath/gnu/java/security/Registry.java465
-rw-r--r--libjava/classpath/gnu/java/security/Requires.java59
-rw-r--r--libjava/classpath/gnu/java/security/action/GetPropertyAction.java89
-rw-r--r--libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java93
-rw-r--r--libjava/classpath/gnu/java/security/action/SetAccessibleAction.java77
-rw-r--r--libjava/classpath/gnu/java/security/action/package.html46
-rw-r--r--libjava/classpath/gnu/java/security/ber/BER.java46
-rw-r--r--libjava/classpath/gnu/java/security/ber/BEREncodingException.java54
-rw-r--r--libjava/classpath/gnu/java/security/ber/BERReader.java103
-rw-r--r--libjava/classpath/gnu/java/security/ber/BERValue.java82
-rw-r--r--libjava/classpath/gnu/java/security/ber/package.html46
-rw-r--r--libjava/classpath/gnu/java/security/der/BitString.java332
-rw-r--r--libjava/classpath/gnu/java/security/der/DER.java86
-rw-r--r--libjava/classpath/gnu/java/security/der/DEREncodingException.java54
-rw-r--r--libjava/classpath/gnu/java/security/der/DERReader.java439
-rw-r--r--libjava/classpath/gnu/java/security/der/DERValue.java189
-rw-r--r--libjava/classpath/gnu/java/security/der/DERWriter.java355
-rw-r--r--libjava/classpath/gnu/java/security/der/package.html46
-rw-r--r--libjava/classpath/gnu/java/security/hash/BaseHash.java183
-rw-r--r--libjava/classpath/gnu/java/security/hash/HashFactory.java135
-rw-r--r--libjava/classpath/gnu/java/security/hash/Haval.java807
-rw-r--r--libjava/classpath/gnu/java/security/hash/IMessageDigest.java127
-rw-r--r--libjava/classpath/gnu/java/security/hash/MD2.java256
-rw-r--r--libjava/classpath/gnu/java/security/hash/MD4.java337
-rw-r--r--libjava/classpath/gnu/java/security/hash/MD5.java371
-rw-r--r--libjava/classpath/gnu/java/security/hash/RipeMD128.java257
-rw-r--r--libjava/classpath/gnu/java/security/hash/RipeMD160.java291
-rw-r--r--libjava/classpath/gnu/java/security/hash/Sha160.java241
-rw-r--r--libjava/classpath/gnu/java/security/hash/Sha256.java252
-rw-r--r--libjava/classpath/gnu/java/security/hash/Sha384.java279
-rw-r--r--libjava/classpath/gnu/java/security/hash/Sha512.java281
-rw-r--r--libjava/classpath/gnu/java/security/hash/Tiger.java864
-rw-r--r--libjava/classpath/gnu/java/security/hash/Whirlpool.java608
-rw-r--r--libjava/classpath/gnu/java/security/jce/hash/HavalSpi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/hash/MD2Spi.java55
-rw-r--r--libjava/classpath/gnu/java/security/jce/hash/MD4Spi.java55
-rw-r--r--libjava/classpath/gnu/java/security/jce/hash/MD5Spi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/hash/MessageDigestAdapter.java133
-rw-r--r--libjava/classpath/gnu/java/security/jce/hash/RipeMD128Spi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/hash/RipeMD160Spi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/hash/Sha160Spi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/hash/Sha256Spi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/hash/Sha384Spi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/hash/Sha512Spi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/hash/TigerSpi.java55
-rw-r--r--libjava/classpath/gnu/java/security/jce/hash/WhirlpoolSpi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/prng/HavalRandomSpi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/prng/MD2RandomSpi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/prng/MD4RandomSpi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/prng/MD5RandomSpi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/prng/RipeMD128RandomSpi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/prng/RipeMD160RandomSpi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/prng/SecureRandomAdapter.java184
-rw-r--r--libjava/classpath/gnu/java/security/jce/prng/Sha160RandomSpi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/prng/Sha256RandomSpi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/prng/Sha384RandomSpi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/prng/Sha512RandomSpi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/prng/TigerRandomSpi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/DSSKeyFactory.java221
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java146
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/DSSParameters.java220
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/DSSParametersGenerator.java125
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/DSSRawSignatureSpi.java56
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/EncodedKeyFactory.java430
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java95
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/MD2withRSA.java56
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/MD5withRSA.java56
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/RSAKeyFactory.java231
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java96
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java56
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/SHA160withDSS.java54
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/SHA160withRSA.java56
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/SHA256withRSA.java56
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/SHA384withRSA.java56
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/SHA512withRSA.java56
-rw-r--r--libjava/classpath/gnu/java/security/jce/sig/SignatureAdapter.java250
-rw-r--r--libjava/classpath/gnu/java/security/key/IKeyPairCodec.java124
-rw-r--r--libjava/classpath/gnu/java/security/key/IKeyPairGenerator.java73
-rw-r--r--libjava/classpath/gnu/java/security/key/KeyPairCodecFactory.java360
-rw-r--r--libjava/classpath/gnu/java/security/key/KeyPairGeneratorFactory.java120
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/DSSKey.java213
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java382
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java249
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java347
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java276
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java205
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java203
-rw-r--r--libjava/classpath/gnu/java/security/key/dss/FIPS186.java262
-rw-r--r--libjava/classpath/gnu/java/security/key/rsa/GnuRSAKey.java178
-rw-r--r--libjava/classpath/gnu/java/security/key/rsa/GnuRSAPrivateKey.java313
-rw-r--r--libjava/classpath/gnu/java/security/key/rsa/GnuRSAPublicKey.java190
-rw-r--r--libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairGenerator.java246
-rw-r--r--libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java299
-rw-r--r--libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java300
-rw-r--r--libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java250
-rw-r--r--libjava/classpath/gnu/java/security/package.html46
-rw-r--r--libjava/classpath/gnu/java/security/pkcs/PKCS7Data.java69
-rw-r--r--libjava/classpath/gnu/java/security/pkcs/PKCS7SignedData.java485
-rw-r--r--libjava/classpath/gnu/java/security/pkcs/SignerInfo.java429
-rw-r--r--libjava/classpath/gnu/java/security/pkcs/package.html46
-rw-r--r--libjava/classpath/gnu/java/security/prng/BasePRNG.java178
-rw-r--r--libjava/classpath/gnu/java/security/prng/EntropySource.java61
-rw-r--r--libjava/classpath/gnu/java/security/prng/IRandom.java174
-rw-r--r--libjava/classpath/gnu/java/security/prng/LimitReachedException.java57
-rw-r--r--libjava/classpath/gnu/java/security/prng/MDGenerator.java127
-rw-r--r--libjava/classpath/gnu/java/security/prng/PRNGFactory.java92
-rw-r--r--libjava/classpath/gnu/java/security/prng/RandomEvent.java81
-rw-r--r--libjava/classpath/gnu/java/security/prng/RandomEventListener.java50
-rw-r--r--libjava/classpath/gnu/java/security/provider/CollectionCertStoreImpl.java102
-rw-r--r--libjava/classpath/gnu/java/security/provider/DefaultPolicy.java68
-rw-r--r--libjava/classpath/gnu/java/security/provider/Gnu.java306
-rw-r--r--libjava/classpath/gnu/java/security/provider/PKIXCertPathValidatorImpl.java693
-rw-r--r--libjava/classpath/gnu/java/security/provider/X509CertificateFactory.java295
-rw-r--r--libjava/classpath/gnu/java/security/provider/package.html46
-rw-r--r--libjava/classpath/gnu/java/security/sig/BaseSignature.java219
-rw-r--r--libjava/classpath/gnu/java/security/sig/ISignature.java160
-rw-r--r--libjava/classpath/gnu/java/security/sig/ISignatureCodec.java59
-rw-r--r--libjava/classpath/gnu/java/security/sig/SignatureCodecFactory.java226
-rw-r--r--libjava/classpath/gnu/java/security/sig/SignatureFactory.java101
-rw-r--r--libjava/classpath/gnu/java/security/sig/dss/DSSSignature.java275
-rw-r--r--libjava/classpath/gnu/java/security/sig/dss/DSSSignatureRawCodec.java164
-rw-r--r--libjava/classpath/gnu/java/security/sig/dss/DSSSignatureX509Codec.java193
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java274
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java243
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java371
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/RSA.java324
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java224
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java153
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java128
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java255
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java134
-rw-r--r--libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java176
-rw-r--r--libjava/classpath/gnu/java/security/util/ByteArray.java111
-rw-r--r--libjava/classpath/gnu/java/security/util/ByteBufferOutputStream.java118
-rw-r--r--libjava/classpath/gnu/java/security/util/DerUtil.java64
-rw-r--r--libjava/classpath/gnu/java/security/util/ExpirableObject.java150
-rw-r--r--libjava/classpath/gnu/java/security/util/FormatUtil.java140
-rw-r--r--libjava/classpath/gnu/java/security/util/IntegerUtil.java109
-rw-r--r--libjava/classpath/gnu/java/security/util/PRNG.java141
-rw-r--r--libjava/classpath/gnu/java/security/util/Prime.java164
-rw-r--r--libjava/classpath/gnu/java/security/util/Sequence.java133
-rw-r--r--libjava/classpath/gnu/java/security/util/SimpleList.java155
-rw-r--r--libjava/classpath/gnu/java/security/util/Util.java629
-rw-r--r--libjava/classpath/gnu/java/security/util/package.html46
-rw-r--r--libjava/classpath/gnu/java/security/x509/GnuPKIExtension.java59
-rw-r--r--libjava/classpath/gnu/java/security/x509/PolicyNodeImpl.java216
-rw-r--r--libjava/classpath/gnu/java/security/x509/Util.java204
-rw-r--r--libjava/classpath/gnu/java/security/x509/X500DistinguishedName.java558
-rw-r--r--libjava/classpath/gnu/java/security/x509/X509CRL.java485
-rw-r--r--libjava/classpath/gnu/java/security/x509/X509CRLEntry.java273
-rw-r--r--libjava/classpath/gnu/java/security/x509/X509CRLSelectorImpl.java137
-rw-r--r--libjava/classpath/gnu/java/security/x509/X509CertPath.java303
-rw-r--r--libjava/classpath/gnu/java/security/x509/X509CertSelectorImpl.java196
-rw-r--r--libjava/classpath/gnu/java/security/x509/X509Certificate.java757
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java133
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/BasicConstraints.java129
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/CRLNumber.java97
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/CertificatePolicies.java205
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/ExtendedKeyUsage.java95
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/Extension.java297
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/GeneralName.java232
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/GeneralNames.java89
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/GeneralSubtree.java156
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/IssuerAlternativeNames.java77
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/KeyUsage.java92
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/NameConstraints.java161
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/PolicyConstraint.java107
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/PolicyMappings.java104
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java105
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/ReasonCode.java85
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/SubjectAlternativeNames.java77
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/SubjectKeyIdentifier.java84
-rw-r--r--libjava/classpath/gnu/java/security/x509/ext/package.html46
-rw-r--r--libjava/classpath/gnu/java/security/x509/package.html46
-rw-r--r--libjava/classpath/gnu/java/text/AttributedFormatBuffer.java251
-rw-r--r--libjava/classpath/gnu/java/text/BaseBreakIterator.java124
-rw-r--r--libjava/classpath/gnu/java/text/CharacterBreakIterator.java213
-rw-r--r--libjava/classpath/gnu/java/text/FormatBuffer.java136
-rw-r--r--libjava/classpath/gnu/java/text/FormatCharacterIterator.java533
-rw-r--r--libjava/classpath/gnu/java/text/LineBreakIterator.java194
-rw-r--r--libjava/classpath/gnu/java/text/SentenceBreakIterator.java247
-rw-r--r--libjava/classpath/gnu/java/text/StringFormatBuffer.java127
-rw-r--r--libjava/classpath/gnu/java/text/WordBreakIterator.java250
-rw-r--r--libjava/classpath/gnu/java/text/package.html46
-rw-r--r--libjava/classpath/gnu/java/util/Base64.java342
-rw-r--r--libjava/classpath/gnu/java/util/DoubleEnumeration.java138
-rw-r--r--libjava/classpath/gnu/java/util/EmptyEnumeration.java90
-rw-r--r--libjava/classpath/gnu/java/util/LRUCache.java77
-rw-r--r--libjava/classpath/gnu/java/util/WeakIdentityHashMap.java862
-rw-r--r--libjava/classpath/gnu/java/util/ZoneInfo.java1160
-rw-r--r--libjava/classpath/gnu/java/util/jar/JarUtils.java451
-rw-r--r--libjava/classpath/gnu/java/util/package.html46
-rw-r--r--libjava/classpath/gnu/java/util/prefs/FileBasedFactory.java65
-rw-r--r--libjava/classpath/gnu/java/util/prefs/FileBasedPreferences.java273
-rw-r--r--libjava/classpath/gnu/java/util/prefs/GConfBasedFactory.java78
-rw-r--r--libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java419
-rw-r--r--libjava/classpath/gnu/java/util/prefs/MemoryBasedFactory.java64
-rw-r--r--libjava/classpath/gnu/java/util/prefs/MemoryBasedPreferences.java144
-rw-r--r--libjava/classpath/gnu/java/util/prefs/NodeReader.java221
-rw-r--r--libjava/classpath/gnu/java/util/prefs/NodeWriter.java319
-rw-r--r--libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java286
-rw-r--r--libjava/classpath/gnu/java/util/prefs/package.html46
-rw-r--r--libjava/classpath/gnu/java/util/regex/BacktrackStack.java124
-rw-r--r--libjava/classpath/gnu/java/util/regex/CharIndexed.java134
-rw-r--r--libjava/classpath/gnu/java/util/regex/CharIndexedCharArray.java48
-rw-r--r--libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java119
-rw-r--r--libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java253
-rw-r--r--libjava/classpath/gnu/java/util/regex/CharIndexedString.java46
-rw-r--r--libjava/classpath/gnu/java/util/regex/CharIndexedStringBuffer.java47
-rw-r--r--libjava/classpath/gnu/java/util/regex/RE.java2675
-rw-r--r--libjava/classpath/gnu/java/util/regex/REException.java198
-rw-r--r--libjava/classpath/gnu/java/util/regex/REFilterInputStream.java153
-rw-r--r--libjava/classpath/gnu/java/util/regex/REMatch.java362
-rw-r--r--libjava/classpath/gnu/java/util/regex/REMatchEnumeration.java141
-rw-r--r--libjava/classpath/gnu/java/util/regex/RESyntax.java537
-rw-r--r--libjava/classpath/gnu/java/util/regex/REToken.java244
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenAny.java115
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenBackRef.java100
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenChar.java162
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenEnd.java151
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenEndOfPreviousMatch.java88
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenEndSub.java79
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenIndependent.java85
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenLookAhead.java88
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenLookBehind.java136
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java410
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenOneOf.java332
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenPOSIX.java195
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenRange.java119
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenRepeated.java639
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenStart.java153
-rw-r--r--libjava/classpath/gnu/java/util/regex/RETokenWordBoundary.java141
-rw-r--r--libjava/classpath/gnu/java/util/regex/UncheckedRE.java114
-rw-r--r--libjava/classpath/gnu/javax/activation/viewers/ImageViewer.java138
-rw-r--r--libjava/classpath/gnu/javax/activation/viewers/TextEditor.java119
-rw-r--r--libjava/classpath/gnu/javax/activation/viewers/TextViewer.java81
-rw-r--r--libjava/classpath/gnu/javax/crypto/RSACipherImpl.java299
-rw-r--r--libjava/classpath/gnu/javax/crypto/assembly/Assembly.java272
-rw-r--r--libjava/classpath/gnu/javax/crypto/assembly/Cascade.java348
-rw-r--r--libjava/classpath/gnu/javax/crypto/assembly/CascadeStage.java93
-rw-r--r--libjava/classpath/gnu/javax/crypto/assembly/CascadeTransformer.java123
-rw-r--r--libjava/classpath/gnu/javax/crypto/assembly/DeflateTransformer.java177
-rw-r--r--libjava/classpath/gnu/javax/crypto/assembly/Direction.java78
-rw-r--r--libjava/classpath/gnu/javax/crypto/assembly/LoopbackTransformer.java100
-rw-r--r--libjava/classpath/gnu/javax/crypto/assembly/ModeStage.java112
-rw-r--r--libjava/classpath/gnu/javax/crypto/assembly/Operation.java73
-rw-r--r--libjava/classpath/gnu/javax/crypto/assembly/PaddingTransformer.java164
-rw-r--r--libjava/classpath/gnu/javax/crypto/assembly/Stage.java202
-rw-r--r--libjava/classpath/gnu/javax/crypto/assembly/Transformer.java421
-rw-r--r--libjava/classpath/gnu/javax/crypto/assembly/TransformerException.java140
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/Anubis.java491
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/BaseCipher.java249
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/Blowfish.java611
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/Cast5.java987
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/CipherFactory.java129
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/DES.java652
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/IBlockCipher.java195
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/IBlockCipherSpi.java124
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/Khazad.java449
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/NullCipher.java108
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/Rijndael.java704
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/Serpent.java1781
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/Square.java425
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/TripleDES.java257
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/Twofish.java737
-rw-r--r--libjava/classpath/gnu/javax/crypto/cipher/WeakKeyException.java59
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/DiffieHellmanImpl.java171
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/GnuCrypto.java598
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/GnuSasl.java124
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/PBKDF2SecretKeyFactory.java218
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/AES128KeyWrapSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/AES192KeyWrapSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/AES256KeyWrapSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/AESKeyWrapSpi.java88
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/AESSpi.java92
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/ARCFourSpi.java183
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/AnubisSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/BlowfishSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/Cast5Spi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/CipherAdapter.java531
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/DESSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/KeyWrappingAlgorithmAdapter.java423
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/KhazadSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/NullCipherSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/PBES2.java1379
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/RijndaelSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/SerpentSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/SquareSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESKeyWrapSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/TripleDESSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/cipher/TwofishSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/AnubisKeyGeneratorImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/AnubisSecretKeyFactoryImpl.java47
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/BlowfishKeyGeneratorImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/BlowfishSecretKeyFactoryImpl.java47
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/Cast5KeyGeneratorImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/Cast5SecretKeyFactoryImpl.java47
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/DESKeyGeneratorImpl.java68
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/DESSecretKeyFactoryImpl.java82
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/DESedeSecretKeyFactoryImpl.java82
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/KhazadKeyGeneratorImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/KhazadSecretKeyFactoryImpl.java47
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/RijndaelKeyGeneratorImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/RijndaelSecretKeyFactoryImpl.java47
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyFactoryImpl.java87
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/SecretKeyGeneratorImpl.java111
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/SerpentKeyGeneratorImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/SerpentSecretKeyFactoryImpl.java47
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/SquareKeyGeneratorImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/SquareSecretKeyFactoryImpl.java47
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/TripleDESKeyGeneratorImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/TwofishKeyGeneratorImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/key/TwofishSecretKeyFactoryImpl.java47
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/keyring/GnuKeyring.java507
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/HMacHavalSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD2Spi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD4Spi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/HMacMD5Spi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD128Spi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/HMacRipeMD160Spi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA160Spi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA256Spi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA384Spi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/HMacSHA512Spi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/HMacTigerSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/HMacWhirlpoolSpi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/MacAdapter.java136
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/OMacAnubisImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/OMacBlowfishImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/OMacCast5Impl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/OMacDESImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/OMacImpl.java140
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/OMacKhazadImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/OMacRijndaelImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/OMacSerpentImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/OMacSquareImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/OMacTripleDESImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/OMacTwofishImpl.java50
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/TMMH16Spi.java81
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/UHash32Spi.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/mac/UMac32Spi.java79
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/params/BlockCipherParameters.java149
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/params/DEREncodingException.java54
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/params/DERReader.java139
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/params/DERWriter.java143
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/prng/ARCFourRandomSpi.java102
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/prng/CSPRNGSpi.java97
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/prng/FortunaImpl.java100
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/prng/ICMRandomSpi.java206
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/prng/UMacRandomSpi.java166
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyFactory.java219
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/sig/DHKeyPairGeneratorSpi.java93
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/sig/DHParameters.java222
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/sig/DHParametersGenerator.java152
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/spec/BlockCipherParameterSpec.java122
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/spec/TMMHParameterSpec.java117
-rw-r--r--libjava/classpath/gnu/javax/crypto/jce/spec/UMac32ParameterSpec.java73
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/BaseKeyAgreementParty.java168
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/GnuPBEKey.java95
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/GnuSecretKey.java131
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/IKeyAgreementParty.java100
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/IncomingMessage.java318
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/KeyAgreementException.java168
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/KeyAgreementFactory.java143
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/OutgoingMessage.java234
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairPKCS8Codec.java240
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairRawCodec.java336
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/DHKeyPairX509Codec.java255
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanKeyAgreement.java119
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanReceiver.java117
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/DiffieHellmanSender.java126
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/ElGamalKeyAgreement.java115
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/ElGamalReceiver.java99
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/ElGamalSender.java112
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKey.java174
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/GnuDHKeyPairGenerator.java235
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPrivateKey.java200
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/GnuDHPublicKey.java196
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/dh/RFC2631.java217
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRP6Host.java161
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRP6KeyAgreement.java141
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslClient.java90
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRP6SaslServer.java90
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSClient.java155
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRP6TLSServer.java177
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRP6User.java163
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRPAlgorithm.java131
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRPKey.java147
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairGenerator.java282
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRPKeyPairRawCodec.java334
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRPPrivateKey.java227
-rw-r--r--libjava/classpath/gnu/javax/crypto/key/srp6/SRPPublicKey.java175
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/AuthenticatedEntry.java176
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/BaseKeyring.java158
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/BinaryDataEntry.java111
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/CertPathEntry.java112
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/CertificateEntry.java128
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/CompressedEntry.java93
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/EncryptedEntry.java191
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/Entry.java179
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/EnvelopeEntry.java439
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/GnuPrivateKeyring.java368
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/GnuPublicKeyring.java151
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/IKeyring.java162
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/IPrivateKeyring.java144
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/IPublicKeyring.java82
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/MalformedKeyringException.java55
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/MaskableEnvelopeEntry.java135
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/MeteredInputStream.java127
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/PasswordAuthenticatedEntry.java286
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/PasswordEncryptedEntry.java293
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/PasswordProtectedEntry.java57
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/PrimitiveEntry.java112
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/PrivateKeyEntry.java194
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/Properties.java203
-rw-r--r--libjava/classpath/gnu/javax/crypto/keyring/PublicKeyEntry.java162
-rw-r--r--libjava/classpath/gnu/javax/crypto/kwa/AESKeyWrap.java168
-rw-r--r--libjava/classpath/gnu/javax/crypto/kwa/BaseKeyWrappingAlgorithm.java145
-rw-r--r--libjava/classpath/gnu/javax/crypto/kwa/IKeyWrappingAlgorithm.java160
-rw-r--r--libjava/classpath/gnu/javax/crypto/kwa/KeyUnwrappingException.java67
-rw-r--r--libjava/classpath/gnu/javax/crypto/kwa/KeyWrappingAlgorithmFactory.java110
-rw-r--r--libjava/classpath/gnu/javax/crypto/kwa/TripleDESKeyWrap.java292
-rw-r--r--libjava/classpath/gnu/javax/crypto/mac/BaseMac.java127
-rw-r--r--libjava/classpath/gnu/javax/crypto/mac/HMac.java263
-rw-r--r--libjava/classpath/gnu/javax/crypto/mac/HMacFactory.java111
-rw-r--r--libjava/classpath/gnu/javax/crypto/mac/IMac.java181
-rw-r--r--libjava/classpath/gnu/javax/crypto/mac/MacFactory.java130
-rw-r--r--libjava/classpath/gnu/javax/crypto/mac/MacInputStream.java124
-rw-r--r--libjava/classpath/gnu/javax/crypto/mac/MacOutputStream.java123
-rw-r--r--libjava/classpath/gnu/javax/crypto/mac/OMAC.java303
-rw-r--r--libjava/classpath/gnu/javax/crypto/mac/TMMH16.java339
-rw-r--r--libjava/classpath/gnu/javax/crypto/mac/UHash32.java758
-rw-r--r--libjava/classpath/gnu/javax/crypto/mac/UMac32.java418
-rw-r--r--libjava/classpath/gnu/javax/crypto/mode/BaseMode.java295
-rw-r--r--libjava/classpath/gnu/javax/crypto/mode/CBC.java123
-rw-r--r--libjava/classpath/gnu/javax/crypto/mode/CFB.java155
-rw-r--r--libjava/classpath/gnu/javax/crypto/mode/CTR.java168
-rw-r--r--libjava/classpath/gnu/javax/crypto/mode/EAX.java289
-rw-r--r--libjava/classpath/gnu/javax/crypto/mode/ECB.java121
-rw-r--r--libjava/classpath/gnu/javax/crypto/mode/IAuthenticatedMode.java56
-rw-r--r--libjava/classpath/gnu/javax/crypto/mode/ICM.java181
-rw-r--r--libjava/classpath/gnu/javax/crypto/mode/IMode.java123
-rw-r--r--libjava/classpath/gnu/javax/crypto/mode/ModeFactory.java151
-rw-r--r--libjava/classpath/gnu/javax/crypto/mode/OFB.java174
-rw-r--r--libjava/classpath/gnu/javax/crypto/pad/BasePad.java193
-rw-r--r--libjava/classpath/gnu/javax/crypto/pad/IPad.java127
-rw-r--r--libjava/classpath/gnu/javax/crypto/pad/ISO10126.java109
-rw-r--r--libjava/classpath/gnu/javax/crypto/pad/PKCS1_V1_5.java156
-rw-r--r--libjava/classpath/gnu/javax/crypto/pad/PKCS7.java111
-rw-r--r--libjava/classpath/gnu/javax/crypto/pad/PadFactory.java120
-rw-r--r--libjava/classpath/gnu/javax/crypto/pad/SSL3.java90
-rw-r--r--libjava/classpath/gnu/javax/crypto/pad/TBC.java118
-rw-r--r--libjava/classpath/gnu/javax/crypto/pad/TLS1.java91
-rw-r--r--libjava/classpath/gnu/javax/crypto/pad/WrongPaddingException.java48
-rw-r--r--libjava/classpath/gnu/javax/crypto/prng/ARCFour.java137
-rw-r--r--libjava/classpath/gnu/javax/crypto/prng/CSPRNG.java985
-rw-r--r--libjava/classpath/gnu/javax/crypto/prng/Fortuna.java349
-rw-r--r--libjava/classpath/gnu/javax/crypto/prng/ICMGenerator.java306
-rw-r--r--libjava/classpath/gnu/javax/crypto/prng/IPBE.java81
-rw-r--r--libjava/classpath/gnu/javax/crypto/prng/PBKDF2.java184
-rw-r--r--libjava/classpath/gnu/javax/crypto/prng/PRNGFactory.java115
-rw-r--r--libjava/classpath/gnu/javax/crypto/prng/UMacGenerator.java186
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/AuthInfo.java129
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/AuthInfoProviderFactory.java67
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/ClientFactory.java168
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/ClientMechanism.java293
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/ConfidentialityException.java82
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProvider.java116
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/IAuthInfoProviderFactory.java55
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/IllegalMechanismStateException.java84
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/InputBuffer.java272
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/IntegrityException.java83
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/NoSuchMechanismException.java62
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/NoSuchUserException.java67
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/OutputBuffer.java198
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/SaslEncodingException.java66
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/SaslInputStream.java393
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/SaslOutputStream.java175
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/SaslUtil.java75
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/ServerFactory.java158
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/ServerMechanism.java294
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/UserAlreadyExistsException.java70
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousClient.java102
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousServer.java90
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/anonymous/AnonymousUtil.java83
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5AuthInfoProvider.java166
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Client.java168
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Registry.java60
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Server.java158
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/crammd5/CramMD5Util.java122
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/crammd5/PasswordFile.java240
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/plain/PasswordFile.java245
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/plain/PlainAuthInfoProvider.java166
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/plain/PlainClient.java156
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/plain/PlainRegistry.java57
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/plain/PlainServer.java155
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/srp/CALG.java221
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/srp/ClientStore.java155
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/srp/IALG.java128
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/srp/KDF.java140
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/srp/PasswordFile.java627
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/srp/SRP.java255
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/srp/SRPAuthInfoProvider.java177
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/srp/SRPClient.java954
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/srp/SRPRegistry.java165
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/srp/SRPServer.java842
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/srp/SecurityContext.java140
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/srp/ServerStore.java177
-rw-r--r--libjava/classpath/gnu/javax/crypto/sasl/srp/StoreEntry.java75
-rw-r--r--libjava/classpath/gnu/javax/imageio/IIOInputStream.java102
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/BMPDecoder.java168
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/BMPEncoder.java119
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/BMPException.java47
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/BMPFileHeader.java151
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/BMPImageReader.java148
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/BMPImageReaderSpi.java116
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/BMPImageWriter.java195
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/BMPImageWriterSpi.java148
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/BMPInfoHeader.java317
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/DecodeBF16.java99
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/DecodeBF32.java103
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB1.java94
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB24.java77
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB4.java90
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB8.java88
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE4.java175
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE8.java142
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB1.java128
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB16.java129
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB24.java129
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB32.java129
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB4.java128
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB8.java127
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE4.java269
-rw-r--r--libjava/classpath/gnu/javax/imageio/bmp/EncodeRLE8.java234
-rw-r--r--libjava/classpath/gnu/javax/imageio/gif/GIFFile.java709
-rw-r--r--libjava/classpath/gnu/javax/imageio/gif/GIFImageReader.java241
-rw-r--r--libjava/classpath/gnu/javax/imageio/gif/GIFImageReaderSpi.java124
-rw-r--r--libjava/classpath/gnu/javax/imageio/jpeg/DCT.java347
-rw-r--r--libjava/classpath/gnu/javax/imageio/jpeg/HuffmanTable.java207
-rw-r--r--libjava/classpath/gnu/javax/imageio/jpeg/JPEGComponent.java351
-rw-r--r--libjava/classpath/gnu/javax/imageio/jpeg/JPEGDecoder.java625
-rw-r--r--libjava/classpath/gnu/javax/imageio/jpeg/JPEGException.java48
-rw-r--r--libjava/classpath/gnu/javax/imageio/jpeg/JPEGFrame.java108
-rw-r--r--libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageInputStream.java188
-rw-r--r--libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReader.java141
-rw-r--r--libjava/classpath/gnu/javax/imageio/jpeg/JPEGImageReaderSpi.java137
-rw-r--r--libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarker.java205
-rw-r--r--libjava/classpath/gnu/javax/imageio/jpeg/JPEGMarkerFoundException.java50
-rw-r--r--libjava/classpath/gnu/javax/imageio/jpeg/JPEGScan.java151
-rw-r--r--libjava/classpath/gnu/javax/imageio/jpeg/YCbCr_ColorSpace.java113
-rw-r--r--libjava/classpath/gnu/javax/imageio/jpeg/ZigZag.java520
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGChunk.java283
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGData.java104
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGDecoder.java331
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGEncoder.java233
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGException.java48
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGFile.java257
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGFilter.java237
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGGamma.java85
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGHeader.java257
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGICCProfile.java116
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGImageReader.java224
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGImageReaderSpi.java128
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGPalette.java127
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGPhys.java112
-rw-r--r--libjava/classpath/gnu/javax/imageio/png/PNGTime.java83
-rw-r--r--libjava/classpath/gnu/javax/management/ListenerData.java136
-rw-r--r--libjava/classpath/gnu/javax/management/Server.java2233
-rw-r--r--libjava/classpath/gnu/javax/management/Translator.java550
-rw-r--r--libjava/classpath/gnu/javax/naming/giop/ContextContinuation.java956
-rw-r--r--libjava/classpath/gnu/javax/naming/giop/CorbalocParser.java441
-rw-r--r--libjava/classpath/gnu/javax/naming/giop/GiopNamingEnumeration.java187
-rw-r--r--libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceFactory.java179
-rw-r--r--libjava/classpath/gnu/javax/naming/giop/GiopNamingServiceURLContext.java840
-rw-r--r--libjava/classpath/gnu/javax/naming/giop/ListBindingsEnumeration.java118
-rw-r--r--libjava/classpath/gnu/javax/naming/giop/ListEnumeration.java118
-rw-r--r--libjava/classpath/gnu/javax/naming/ictxImpl/trans/GnuName.java469
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/corbaname/corbanameURLContextFactory.java53
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/rmi/ContextContinuation.java597
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListBindingsEnumeration.java97
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/rmi/ListEnumeration.java80
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiContinuation.java594
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/rmi/RmiNamingEnumeration.java130
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContext.java637
-rw-r--r--libjava/classpath/gnu/javax/naming/jndi/url/rmi/rmiURLContextFactory.java66
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/AbstractSessionContext.java288
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/EntropySource.java62
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/NullManagerParameters.java56
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManager.java54
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/PreSharedKeyManagerParameters.java83
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/PrivateCredentials.java363
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/SRPManagerParameters.java81
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/SRPTrustManager.java99
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/SSLCipherSuite.java142
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/SSLProtocolVersion.java54
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/SSLRecordHandler.java100
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/Session.java366
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/SessionStoreException.java59
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/StaticTrustAnchors.java1940
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/AbstractHandshake.java1205
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Alert.java288
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/AlertException.java101
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Builder.java66
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Certificate.java177
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateBuilder.java94
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequest.java155
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateRequestBuilder.java111
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusRequest.java272
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateStatusType.java13
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateType.java62
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateURL.java388
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CertificateVerify.java83
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CipherAlgorithm.java47
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CipherSuite.java837
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CipherSuiteList.java283
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientCertificateTypeList.java227
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientDHE_PSKParameters.java122
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientDiffieHellmanPublic.java129
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientHandshake.java1153
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientHello.java240
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloBuilder.java137
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientHelloV2.java158
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchange.java132
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientKeyExchangeBuilder.java75
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientPSKParameters.java121
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ClientRSA_PSKParameters.java122
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethod.java69
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/CompressionMethodList.java281
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Constructed.java86
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ContentType.java89
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Debug.java66
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/DelegatedTask.java93
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/DiffieHellman.java289
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/EmptyExchangeKeys.java77
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/EncryptedPreMasterSecret.java148
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ExchangeKeys.java54
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Extension.java246
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ExtensionList.java290
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Finished.java173
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Handshake.java299
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/HelloRequest.java72
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/InputSecurityParameters.java334
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Jessie.java102
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/KeyExchangeAlgorithm.java57
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/MacAlgorithm.java47
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/MacException.java53
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/MaxFragmentLength.java59
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/OutputSecurityParameters.java294
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/PreSharedKeyManagerFactoryImpl.java118
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ProtocolVersion.java200
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Random.java150
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Record.java198
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SRPTrustManagerFactory.java223
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLContextImpl.java315
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLEngineImpl.java842
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLHMac.java158
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLRSASignatureImpl.java234
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLRandom.java165
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketFactoryImpl.java108
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLServerSocketImpl.java199
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketFactoryImpl.java143
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLSocketImpl.java740
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacMD5Impl.java116
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SSLv3HMacSHAImpl.java116
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerDHE_PSKParameters.java148
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerDHParams.java248
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerHandshake.java1377
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerHello.java231
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloBuilder.java131
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerHelloDone.java66
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchange.java173
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeBuilder.java89
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerKeyExchangeParams.java50
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerNameList.java311
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerPSKParameters.java127
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerRSAParams.java163
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/ServerRSA_PSKParameters.java62
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SessionImpl.java192
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Signature.java157
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SignatureAlgorithm.java62
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/SimpleSessionContext.java144
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/TLSHMac.java137
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/TLSRandom.java252
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/TruncatedHMAC.java76
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/TrustedAuthorities.java297
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/UnresolvedExtensionValue.java81
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/Util.java495
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/X500PrincipalList.java272
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/X509KeyManagerFactory.java396
-rw-r--r--libjava/classpath/gnu/javax/net/ssl/provider/X509TrustManagerFactory.java295
-rw-r--r--libjava/classpath/gnu/javax/print/CupsIppOperation.java99
-rw-r--r--libjava/classpath/gnu/javax/print/CupsMediaMapping.java176
-rw-r--r--libjava/classpath/gnu/javax/print/CupsPrintService.java104
-rw-r--r--libjava/classpath/gnu/javax/print/CupsPrintServiceLookup.java260
-rw-r--r--libjava/classpath/gnu/javax/print/CupsServer.java288
-rw-r--r--libjava/classpath/gnu/javax/print/PrintAttributeException.java148
-rw-r--r--libjava/classpath/gnu/javax/print/PrintFlavorException.java120
-rw-r--r--libjava/classpath/gnu/javax/print/PrintUriException.java140
-rw-r--r--libjava/classpath/gnu/javax/print/PrinterDialog.java1722
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/DocPrintJobImpl.java471
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/IppDelimiterTag.java99
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/IppException.java88
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/IppMultiDocPrintService.java87
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/IppPrintService.java924
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/IppRequest.java875
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/IppResponse.java787
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/IppStatusCode.java185
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/IppUtilities.java553
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/IppValueTag.java170
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/MultiDocPrintJobImpl.java80
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/CharsetSyntax.java115
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/DefaultValueAttribute.java59
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/DetailedStatusMessage.java93
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/DocumentAccessError.java93
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/NaturalLanguageSyntax.java117
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/RequestedAttributes.java132
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/StatusMessage.java92
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/UnknownAttribute.java190
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/defaults/CopiesDefault.java118
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/defaults/DocumentFormatDefault.java106
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/defaults/FinishingsDefault.java263
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobHoldUntilDefault.java149
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobPriorityDefault.java118
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/defaults/JobSheetsDefault.java122
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MediaDefault.java105
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/defaults/MultipleDocumentHandlingDefault.java152
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/defaults/NumberUpDefault.java114
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/defaults/OrientationRequestedDefault.java154
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrintQualityDefault.java141
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/defaults/PrinterResolutionDefault.java119
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/defaults/SidesDefault.java150
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesCharset.java93
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/job/AttributesNaturalLanguage.java95
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDetailedStatusMessages.java92
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/job/JobDocumentAccessErrors.java93
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/job/JobId.java87
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/job/JobMoreInfo.java87
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/job/JobPrinterUri.java87
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/job/JobStateMessage.java92
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/job/JobUri.java87
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/printer/CharsetConfigured.java86
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/printer/DocumentFormat.java111
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/printer/MultipleOperationTimeOut.java86
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/printer/NaturalLanguageConfigured.java86
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterCurrentTime.java107
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterDriverInstaller.java88
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterStateMessage.java94
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/printer/PrinterUpTime.java86
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/CharsetSupported.java88
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/CompressionSupported.java161
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/DocumentFormatSupported.java92
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/FinishingsSupported.java302
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/GeneratedNaturalLanguageSupported.java89
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/IppVersionsSupported.java122
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobHoldUntilSupported.java134
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/JobSheetsSupported.java148
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/MediaSupported.java116
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentHandlingSupported.java176
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/MultipleDocumentJobsSupported.java119
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/OperationsSupported.java231
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/OrientationRequestedSupported.java178
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/PageRangesSupported.java117
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrintQualitySupported.java169
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterResolutionSupported.java142
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/PrinterUriSupported.java89
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/SidesSupported.java137
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriAuthenticationSupported.java142
-rw-r--r--libjava/classpath/gnu/javax/print/ipp/attribute/supported/UriSecuritySupported.java127
-rw-r--r--libjava/classpath/gnu/javax/rmi/CORBA/CorbaInput.java297
-rw-r--r--libjava/classpath/gnu/javax/rmi/CORBA/CorbaOutput.java219
-rw-r--r--libjava/classpath/gnu/javax/rmi/CORBA/DefaultWriteObjectTester.java85
-rw-r--r--libjava/classpath/gnu/javax/rmi/CORBA/DelegateFactory.java107
-rw-r--r--libjava/classpath/gnu/javax/rmi/CORBA/GetDelegateInstanceException.java55
-rw-r--r--libjava/classpath/gnu/javax/rmi/CORBA/PortableRemoteObjectDelegateImpl.java362
-rw-r--r--libjava/classpath/gnu/javax/rmi/CORBA/RmiUtilities.java949
-rw-r--r--libjava/classpath/gnu/javax/rmi/CORBA/StubDelegateImpl.java310
-rw-r--r--libjava/classpath/gnu/javax/rmi/CORBA/TieTargetRecord.java93
-rw-r--r--libjava/classpath/gnu/javax/rmi/CORBA/UtilDelegateImpl.java744
-rw-r--r--libjava/classpath/gnu/javax/rmi/CORBA/ValueHandlerDelegateImpl.java163
-rw-r--r--libjava/classpath/gnu/javax/security/auth/Password.java283
-rw-r--r--libjava/classpath/gnu/javax/security/auth/callback/AWTCallbackHandler.java454
-rw-r--r--libjava/classpath/gnu/javax/security/auth/callback/AbstractCallbackHandler.java295
-rw-r--r--libjava/classpath/gnu/javax/security/auth/callback/CertificateCallback.java64
-rw-r--r--libjava/classpath/gnu/javax/security/auth/callback/ConsoleCallbackHandler.java299
-rw-r--r--libjava/classpath/gnu/javax/security/auth/callback/DefaultCallbackHandler.java109
-rw-r--r--libjava/classpath/gnu/javax/security/auth/callback/GnuCallbacks.java64
-rw-r--r--libjava/classpath/gnu/javax/security/auth/callback/SwingCallbackHandler.java587
-rw-r--r--libjava/classpath/gnu/javax/security/auth/login/ConfigFileParser.java346
-rw-r--r--libjava/classpath/gnu/javax/security/auth/login/ConfigFileTokenizer.java246
-rw-r--r--libjava/classpath/gnu/javax/security/auth/login/GnuConfiguration.java466
-rw-r--r--libjava/classpath/gnu/javax/sound/AudioSecurityManager.java112
-rw-r--r--libjava/classpath/gnu/javax/sound/midi/alsa/AlsaInputPortDevice.java130
-rw-r--r--libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiDeviceProvider.java216
-rw-r--r--libjava/classpath/gnu/javax/sound/midi/alsa/AlsaMidiSequencerDevice.java515
-rw-r--r--libjava/classpath/gnu/javax/sound/midi/alsa/AlsaOutputPortDevice.java131
-rw-r--r--libjava/classpath/gnu/javax/sound/midi/alsa/AlsaPortDevice.java150
-rw-r--r--libjava/classpath/gnu/javax/sound/midi/dssi/DSSIMidiDeviceProvider.java171
-rw-r--r--libjava/classpath/gnu/javax/sound/midi/dssi/DSSISynthesizer.java742
-rw-r--r--libjava/classpath/gnu/javax/sound/midi/file/ExtendedMidiFileFormat.java77
-rw-r--r--libjava/classpath/gnu/javax/sound/midi/file/MidiDataInputStream.java83
-rw-r--r--libjava/classpath/gnu/javax/sound/midi/file/MidiDataOutputStream.java114
-rw-r--r--libjava/classpath/gnu/javax/sound/midi/file/MidiFileReader.java378
-rw-r--r--libjava/classpath/gnu/javax/sound/midi/file/MidiFileWriter.java197
-rw-r--r--libjava/classpath/gnu/javax/sound/sampled/AU/AUReader.java210
-rw-r--r--libjava/classpath/gnu/javax/sound/sampled/WAV/WAVReader.java236
-rw-r--r--libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixer.java248
-rw-r--r--libjava/classpath/gnu/javax/sound/sampled/gstreamer/GStreamerMixerProvider.java71
-rw-r--r--libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReader.java185
-rw-r--r--libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileReaderNativePeer.java284
-rw-r--r--libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstAudioFileWriter.java80
-rw-r--r--libjava/classpath/gnu/javax/sound/sampled/gstreamer/io/GstInputStream.java119
-rw-r--r--libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstDataLine.java151
-rw-r--r--libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstNativeDataLine.java77
-rw-r--r--libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstPipeline.java415
-rw-r--r--libjava/classpath/gnu/javax/sound/sampled/gstreamer/lines/GstSourceDataLine.java153
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/gnu/GNULookAndFeel.java266
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Error.pngbin0 -> 1335 bytes
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Inform.pngbin0 -> 250 bytes
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCup.pngbin0 -> 512 bytes
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCupLarge.pngbin0 -> 4341 bytes
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Question.pngbin0 -> 250 bytes
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/gtk/icons/README20
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeClosed.pngbin0 -> 390 bytes
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf-normal.pngbin0 -> 1522 bytes
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf.pngbin0 -> 1007 bytes
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeOpen.pngbin0 -> 315 bytes
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Warn.pngbin0 -> 1335 bytes
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/gtk/icons/file-folders.pngbin0 -> 843 bytes
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/gtk/icons/slider.pngbin0 -> 179 bytes
-rw-r--r--libjava/classpath/gnu/javax/swing/plaf/metal/CustomizableTheme.java218
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/CharacterAttributeTranslator.java192
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/CombinedAttributes.java213
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/ImageViewIconFactory.java282
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/BorderStyle.java64
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/BorderWidth.java78
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/CSSColor.java170
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/CSSLexicalException.java60
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/CSSParser.java503
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/CSSParserCallback.java81
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/CSSParserException.java62
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/CSSScanner.java718
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/FontSize.java273
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/FontStyle.java80
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/FontWeight.java84
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/Length.java283
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/css/Selector.java245
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/package.html50
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/GnuParserDelegator.java179
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/HTML_401F.java3801
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/SmallHtmlAttributeSet.java261
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/gnuDTD.java421
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/htmlAttributeSet.java183
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/htmlValidator.java622
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/models/PCDATAonly_model.java62
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/models/TableRowContentModel.java77
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/models/list.java384
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/models/noTagModel.java75
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/models/node.java339
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/models/package.html53
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/models/transformer.java201
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/package.html51
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/Parser.java1532
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/gnuStringIntMapper.java112
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Buffer.java238
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Constants.java433
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Location.java83
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ParseException.java51
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Queue.java142
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/low/ReaderTokenizer.java373
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/low/Token.java169
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/low/node.java78
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/low/package.html47
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/low/pattern.java105
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/package.html47
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/parameterDefaulter.java106
-rw-r--r--libjava/classpath/gnu/javax/swing/text/html/parser/support/textPreProcessor.java189
-rw-r--r--libjava/classpath/gnu/javax/swing/tree/GnuPath.java65
-rw-r--r--libjava/classpath/gnu/test/.cvsignore1
-rw-r--r--libjava/classpath/gnu/test/Fail.java57
-rw-r--r--libjava/classpath/gnu/test/Makefile.am5
-rw-r--r--libjava/classpath/gnu/test/Pass.java57
-rw-r--r--libjava/classpath/gnu/test/Result.java85
-rw-r--r--libjava/classpath/gnu/test/Test.java57
-rw-r--r--libjava/classpath/gnu/test/Unresolved.java57
-rw-r--r--libjava/classpath/gnu/test/Unsupported.java59
-rw-r--r--libjava/classpath/gnu/test/Untested.java57
-rw-r--r--libjava/classpath/gnu/test/XFail.java57
-rw-r--r--libjava/classpath/gnu/test/XPass.java56
-rw-r--r--libjava/classpath/gnu/xml/aelfred2/JAXPFactory.java230
-rw-r--r--libjava/classpath/gnu/xml/aelfred2/SAXDriver.java1609
-rw-r--r--libjava/classpath/gnu/xml/aelfred2/XmlParser.java5831
-rw-r--r--libjava/classpath/gnu/xml/aelfred2/XmlReader.java373
-rw-r--r--libjava/classpath/gnu/xml/aelfred2/package.html506
-rw-r--r--libjava/classpath/gnu/xml/dom/Consumer.java352
-rw-r--r--libjava/classpath/gnu/xml/dom/DTDAttributeTypeInfo.java83
-rw-r--r--libjava/classpath/gnu/xml/dom/DTDElementTypeInfo.java111
-rw-r--r--libjava/classpath/gnu/xml/dom/DomAttr.java411
-rw-r--r--libjava/classpath/gnu/xml/dom/DomCDATASection.java90
-rw-r--r--libjava/classpath/gnu/xml/dom/DomCharacterData.java344
-rw-r--r--libjava/classpath/gnu/xml/dom/DomComment.java80
-rw-r--r--libjava/classpath/gnu/xml/dom/DomDOMException.java174
-rw-r--r--libjava/classpath/gnu/xml/dom/DomDoctype.java455
-rw-r--r--libjava/classpath/gnu/xml/dom/DomDocument.java1555
-rw-r--r--libjava/classpath/gnu/xml/dom/DomDocumentBuilder.java227
-rw-r--r--libjava/classpath/gnu/xml/dom/DomDocumentBuilderFactory.java181
-rw-r--r--libjava/classpath/gnu/xml/dom/DomDocumentConfiguration.java260
-rw-r--r--libjava/classpath/gnu/xml/dom/DomDocumentFragment.java75
-rw-r--r--libjava/classpath/gnu/xml/dom/DomElement.java582
-rw-r--r--libjava/classpath/gnu/xml/dom/DomEntity.java146
-rw-r--r--libjava/classpath/gnu/xml/dom/DomEntityReference.java130
-rw-r--r--libjava/classpath/gnu/xml/dom/DomEvent.java351
-rw-r--r--libjava/classpath/gnu/xml/dom/DomExtern.java116
-rw-r--r--libjava/classpath/gnu/xml/dom/DomImpl.java277
-rw-r--r--libjava/classpath/gnu/xml/dom/DomIterator.java380
-rw-r--r--libjava/classpath/gnu/xml/dom/DomNSResolverContext.java90
-rw-r--r--libjava/classpath/gnu/xml/dom/DomNamedNodeMap.java421
-rw-r--r--libjava/classpath/gnu/xml/dom/DomNode.java2222
-rw-r--r--libjava/classpath/gnu/xml/dom/DomNodeIterator.java328
-rw-r--r--libjava/classpath/gnu/xml/dom/DomNotation.java102
-rw-r--r--libjava/classpath/gnu/xml/dom/DomNsNode.java226
-rw-r--r--libjava/classpath/gnu/xml/dom/DomProcessingInstruction.java146
-rw-r--r--libjava/classpath/gnu/xml/dom/DomText.java222
-rw-r--r--libjava/classpath/gnu/xml/dom/DomXPathExpression.java147
-rw-r--r--libjava/classpath/gnu/xml/dom/DomXPathNSResolver.java64
-rw-r--r--libjava/classpath/gnu/xml/dom/DomXPathResult.java233
-rw-r--r--libjava/classpath/gnu/xml/dom/ImplementationList.java70
-rw-r--r--libjava/classpath/gnu/xml/dom/ImplementationSource.java167
-rw-r--r--libjava/classpath/gnu/xml/dom/JAXPFactory.java308
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLAnchorElement.java188
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLAppletElement.java187
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLAreaElement.java138
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLBRElement.java68
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseElement.java78
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLBaseFontElement.java88
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLBodyElement.java118
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLButtonElement.java119
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLCollection.java225
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLDListElement.java68
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLDirectoryElement.java68
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLDivElement.java68
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLDocument.java426
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLElement.java286
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLEmbedElement.java129
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLFieldSetElement.java64
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLFontElement.java88
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLFormElement.java149
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameElement.java145
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLFrameSetElement.java78
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLHRElement.java98
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadElement.java68
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLHeadingElement.java68
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLHtmlElement.java68
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLIFrameElement.java165
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLImageElement.java178
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLImpl.java66
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLInputElement.java265
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLIsIndexElement.java74
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLLIElement.java78
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLLabelElement.java84
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLLegendElement.java84
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLLinkElement.java148
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLMapElement.java78
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLMenuElement.java68
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLMetaElement.java98
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLModElement.java78
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLOListElement.java88
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLObjectElement.java320
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLOptGroupElement.java78
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLOptionElement.java130
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLParagraphElement.java68
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLParamElement.java98
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLParser.java264
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLPreElement.java68
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLQuoteElement.java68
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLScriptElement.java128
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLSelectElement.java210
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLStyleElement.java88
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCaptionElement.java69
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLTableCellElement.java204
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLTableColElement.java119
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLTableElement.java397
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLTableRowElement.java228
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLTableSectionElement.java162
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLTextAreaElement.java181
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLTitleElement.java68
-rw-r--r--libjava/classpath/gnu/xml/dom/html2/DomHTMLUListElement.java78
-rw-r--r--libjava/classpath/gnu/xml/dom/ls/DomLSException.java57
-rw-r--r--libjava/classpath/gnu/xml/dom/ls/DomLSInput.java159
-rw-r--r--libjava/classpath/gnu/xml/dom/ls/DomLSOutput.java98
-rw-r--r--libjava/classpath/gnu/xml/dom/ls/DomLSParser.java567
-rw-r--r--libjava/classpath/gnu/xml/dom/ls/DomLSSerializer.java353
-rw-r--r--libjava/classpath/gnu/xml/dom/ls/FilteredSAXEventSink.java353
-rw-r--r--libjava/classpath/gnu/xml/dom/ls/ReaderInputStream.java236
-rw-r--r--libjava/classpath/gnu/xml/dom/ls/SAXEventSink.java603
-rw-r--r--libjava/classpath/gnu/xml/dom/ls/WriterOutputStream.java97
-rw-r--r--libjava/classpath/gnu/xml/dom/package.html273
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeAttr.java117
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeCDATASection.java57
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeCharacterData.java119
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeComment.java57
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMException.java98
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeDOMStringList.java84
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocument.java562
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilder.java326
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentBuilderFactory.java118
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentFragment.java57
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeDocumentType.java98
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeElement.java184
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntity.java104
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeEntityReference.java57
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeNamedNodeMap.java92
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeNode.java501
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeNodeList.java66
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeNotation.java80
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeProcessingInstruction.java79
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeText.java132
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeTypeInfo.java65
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathExpression.java86
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNSResolver.java64
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathNodeList.java73
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/dom/GnomeXPathResult.java134
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/sax/GnomeLocator.java99
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParser.java105
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/sax/GnomeSAXParserFactory.java92
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/sax/GnomeXMLReader.java1065
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/sax/Namespaces.java122
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/sax/StringArrayAttributes.java170
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/sax/XMLName.java92
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/transform/ErrorListenerErrorHandler.java111
-rwxr-xr-xlibjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformer.java572
-rwxr-xr-xlibjava/classpath/gnu/xml/libxmlj/transform/GnomeTransformerFactory.java349
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/transform/URIResolverEntityResolver.java87
-rwxr-xr-xlibjava/classpath/gnu/xml/libxmlj/transform/package.html14
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/util/EmptyNodeList.java62
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/util/NamedInputStream.java99
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/util/StandaloneDocumentType.java294
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/util/StandaloneLocator.java89
-rw-r--r--libjava/classpath/gnu/xml/libxmlj/util/XMLJ.java280
-rw-r--r--libjava/classpath/gnu/xml/pipeline/CallFilter.java257
-rw-r--r--libjava/classpath/gnu/xml/pipeline/DomConsumer.java967
-rw-r--r--libjava/classpath/gnu/xml/pipeline/EventConsumer.java95
-rw-r--r--libjava/classpath/gnu/xml/pipeline/EventFilter.java796
-rw-r--r--libjava/classpath/gnu/xml/pipeline/LinkFilter.java242
-rw-r--r--libjava/classpath/gnu/xml/pipeline/NSFilter.java341
-rw-r--r--libjava/classpath/gnu/xml/pipeline/PipelineFactory.java723
-rw-r--r--libjava/classpath/gnu/xml/pipeline/TeeConsumer.java417
-rw-r--r--libjava/classpath/gnu/xml/pipeline/TextConsumer.java117
-rw-r--r--libjava/classpath/gnu/xml/pipeline/ValidationConsumer.java1928
-rw-r--r--libjava/classpath/gnu/xml/pipeline/WellFormednessFilter.java363
-rw-r--r--libjava/classpath/gnu/xml/pipeline/XIncludeFilter.java579
-rw-r--r--libjava/classpath/gnu/xml/pipeline/XsltFilter.java130
-rw-r--r--libjava/classpath/gnu/xml/pipeline/package.html255
-rw-r--r--libjava/classpath/gnu/xml/stream/AttributeImpl.java123
-rw-r--r--libjava/classpath/gnu/xml/stream/BufferedReader.java198
-rw-r--r--libjava/classpath/gnu/xml/stream/CRLFReader.java180
-rw-r--r--libjava/classpath/gnu/xml/stream/CharactersImpl.java119
-rw-r--r--libjava/classpath/gnu/xml/stream/CommentImpl.java91
-rw-r--r--libjava/classpath/gnu/xml/stream/DTDImpl.java114
-rw-r--r--libjava/classpath/gnu/xml/stream/EndDocumentImpl.java70
-rw-r--r--libjava/classpath/gnu/xml/stream/EndElementImpl.java107
-rw-r--r--libjava/classpath/gnu/xml/stream/EntityDeclarationImpl.java163
-rw-r--r--libjava/classpath/gnu/xml/stream/EntityReferenceImpl.java101
-rw-r--r--libjava/classpath/gnu/xml/stream/FilteredEventReader.java114
-rw-r--r--libjava/classpath/gnu/xml/stream/FilteredStreamReader.java90
-rw-r--r--libjava/classpath/gnu/xml/stream/NamespaceImpl.java137
-rw-r--r--libjava/classpath/gnu/xml/stream/NotationDeclarationImpl.java125
-rw-r--r--libjava/classpath/gnu/xml/stream/ProcessingInstructionImpl.java104
-rw-r--r--libjava/classpath/gnu/xml/stream/SAXParser.java1041
-rw-r--r--libjava/classpath/gnu/xml/stream/SAXParserFactory.java104
-rw-r--r--libjava/classpath/gnu/xml/stream/StartDocumentImpl.java143
-rw-r--r--libjava/classpath/gnu/xml/stream/StartElementImpl.java152
-rw-r--r--libjava/classpath/gnu/xml/stream/UnicodeReader.java205
-rw-r--r--libjava/classpath/gnu/xml/stream/XIncludeFilter.java931
-rw-r--r--libjava/classpath/gnu/xml/stream/XMLEventAllocatorImpl.java204
-rw-r--r--libjava/classpath/gnu/xml/stream/XMLEventFactoryImpl.java269
-rw-r--r--libjava/classpath/gnu/xml/stream/XMLEventImpl.java198
-rw-r--r--libjava/classpath/gnu/xml/stream/XMLEventReaderImpl.java157
-rw-r--r--libjava/classpath/gnu/xml/stream/XMLEventWriterImpl.java190
-rw-r--r--libjava/classpath/gnu/xml/stream/XMLInputFactoryImpl.java397
-rw-r--r--libjava/classpath/gnu/xml/stream/XMLOutputFactoryImpl.java187
-rw-r--r--libjava/classpath/gnu/xml/stream/XMLParser.java5434
-rw-r--r--libjava/classpath/gnu/xml/stream/XMLStreamWriterImpl.java1016
-rw-r--r--libjava/classpath/gnu/xml/transform/AbstractNumberNode.java330
-rw-r--r--libjava/classpath/gnu/xml/transform/ApplyImportsNode.java82
-rw-r--r--libjava/classpath/gnu/xml/transform/ApplyTemplatesNode.java219
-rw-r--r--libjava/classpath/gnu/xml/transform/AttributeNode.java244
-rw-r--r--libjava/classpath/gnu/xml/transform/AttributeSet.java66
-rw-r--r--libjava/classpath/gnu/xml/transform/Bindings.java346
-rw-r--r--libjava/classpath/gnu/xml/transform/CallTemplateNode.java156
-rw-r--r--libjava/classpath/gnu/xml/transform/ChooseNode.java88
-rw-r--r--libjava/classpath/gnu/xml/transform/CommentNode.java103
-rw-r--r--libjava/classpath/gnu/xml/transform/CopyNode.java168
-rw-r--r--libjava/classpath/gnu/xml/transform/CopyOfNode.java174
-rw-r--r--libjava/classpath/gnu/xml/transform/CurrentFunction.java103
-rw-r--r--libjava/classpath/gnu/xml/transform/DOMSourceLocator.java84
-rw-r--r--libjava/classpath/gnu/xml/transform/DocumentFunction.java244
-rw-r--r--libjava/classpath/gnu/xml/transform/ElementAvailableFunction.java181
-rw-r--r--libjava/classpath/gnu/xml/transform/ElementNode.java261
-rw-r--r--libjava/classpath/gnu/xml/transform/ErrorListenerErrorHandler.java101
-rw-r--r--libjava/classpath/gnu/xml/transform/ForEachNode.java159
-rw-r--r--libjava/classpath/gnu/xml/transform/FormatNumberFunction.java145
-rw-r--r--libjava/classpath/gnu/xml/transform/FunctionAvailableFunction.java192
-rw-r--r--libjava/classpath/gnu/xml/transform/GenerateIdFunction.java139
-rw-r--r--libjava/classpath/gnu/xml/transform/IfNode.java112
-rw-r--r--libjava/classpath/gnu/xml/transform/Key.java70
-rw-r--r--libjava/classpath/gnu/xml/transform/KeyFunction.java227
-rw-r--r--libjava/classpath/gnu/xml/transform/LiteralNode.java202
-rw-r--r--libjava/classpath/gnu/xml/transform/MessageNode.java110
-rw-r--r--libjava/classpath/gnu/xml/transform/NamespaceProxy.java77
-rw-r--r--libjava/classpath/gnu/xml/transform/NodeNumberNode.java269
-rw-r--r--libjava/classpath/gnu/xml/transform/NumberNode.java88
-rw-r--r--libjava/classpath/gnu/xml/transform/OtherwiseNode.java83
-rw-r--r--libjava/classpath/gnu/xml/transform/ParameterNode.java172
-rw-r--r--libjava/classpath/gnu/xml/transform/ProcessingInstructionNode.java118
-rw-r--r--libjava/classpath/gnu/xml/transform/SAXSerializer.java305
-rw-r--r--libjava/classpath/gnu/xml/transform/SAXTemplatesHandler.java97
-rw-r--r--libjava/classpath/gnu/xml/transform/SAXTransformerHandler.java111
-rw-r--r--libjava/classpath/gnu/xml/transform/SortKey.java239
-rw-r--r--libjava/classpath/gnu/xml/transform/StreamSerializer.java854
-rw-r--r--libjava/classpath/gnu/xml/transform/StrippingInstruction.java73
-rw-r--r--libjava/classpath/gnu/xml/transform/Stylesheet.java1772
-rw-r--r--libjava/classpath/gnu/xml/transform/SystemPropertyFunction.java140
-rw-r--r--libjava/classpath/gnu/xml/transform/Template.java263
-rw-r--r--libjava/classpath/gnu/xml/transform/TemplateNode.java130
-rw-r--r--libjava/classpath/gnu/xml/transform/TemplatesImpl.java95
-rw-r--r--libjava/classpath/gnu/xml/transform/TextNode.java121
-rw-r--r--libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java438
-rw-r--r--libjava/classpath/gnu/xml/transform/TransformerImpl.java805
-rw-r--r--libjava/classpath/gnu/xml/transform/TransformerOutputProperties.java186
-rw-r--r--libjava/classpath/gnu/xml/transform/URIResolverEntityResolver.java83
-rw-r--r--libjava/classpath/gnu/xml/transform/UnparsedEntityUriFunction.java132
-rw-r--r--libjava/classpath/gnu/xml/transform/ValueOfNode.java141
-rw-r--r--libjava/classpath/gnu/xml/transform/WhenNode.java115
-rw-r--r--libjava/classpath/gnu/xml/transform/WithParam.java127
-rw-r--r--libjava/classpath/gnu/xml/transform/XSLComparator.java118
-rw-r--r--libjava/classpath/gnu/xml/transform/XSLURIResolver.java321
-rw-r--r--libjava/classpath/gnu/xml/transform/package.html77
-rw-r--r--libjava/classpath/gnu/xml/util/DoParse.java302
-rw-r--r--libjava/classpath/gnu/xml/util/DomParser.java804
-rw-r--r--libjava/classpath/gnu/xml/util/Resolver.java263
-rw-r--r--libjava/classpath/gnu/xml/util/SAXNullTransformerFactory.java676
-rw-r--r--libjava/classpath/gnu/xml/util/XCat.java1611
-rw-r--r--libjava/classpath/gnu/xml/util/XHTMLWriter.java114
-rw-r--r--libjava/classpath/gnu/xml/util/XMLWriter.java1931
-rw-r--r--libjava/classpath/gnu/xml/util/package.html20
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/Annotation.java60
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/AnySimpleType.java58
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/AnyType.java57
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/AnyURIType.java93
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/AtomicSimpleType.java77
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/Base64BinaryType.java128
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/BooleanType.java89
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/ByteType.java132
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/DateTimeType.java334
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/DateType.java221
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/DecimalType.java118
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/DoubleType.java110
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/DurationType.java238
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/EntitiesType.java108
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/EntityType.java87
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/EnumerationFacet.java68
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/Facet.java77
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/FloatType.java110
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/FractionDigitsFacet.java71
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/GDayType.java174
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/GMonthDayType.java183
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/GMonthType.java163
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/GYearMonthType.java176
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/GYearType.java151
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/HexBinaryType.java89
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/IDRefType.java86
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/IDRefsType.java86
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/IDType.java86
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/IntType.java132
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/IntegerType.java109
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/LanguageType.java86
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/LengthFacet.java71
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/ListSimpleType.java82
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/LongType.java132
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/MaxExclusiveFacet.java110
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/MaxInclusiveFacet.java111
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/MaxLengthFacet.java71
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/MinExclusiveFacet.java110
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/MinInclusiveFacet.java111
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/MinLengthFacet.java71
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/NCNameType.java110
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/NMTokenType.java101
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/NMTokensType.java125
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/NameType.java103
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/NegativeIntegerType.java110
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/NonNegativeIntegerType.java120
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/NonPositiveIntegerType.java120
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/NormalizedStringType.java87
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/NotationType.java87
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/PatternFacet.java70
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/PositiveIntegerType.java110
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/QNameType.java121
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/ShortType.java132
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/SimpleType.java255
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/StringType.java72
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/TimeType.java302
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/TokenType.java95
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/TotalDigitsFacet.java71
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/Type.java62
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/TypeBuilder.java278
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/TypeLibrary.java173
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/TypeLibraryFactory.java60
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/UnionSimpleType.java82
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/UnsignedByteType.java120
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/UnsignedIntType.java120
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/UnsignedLongType.java120
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/UnsignedShortType.java121
-rw-r--r--libjava/classpath/gnu/xml/validation/datatype/WhiteSpaceFacet.java74
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/AnyNameNameClass.java57
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/AttributePattern.java52
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/ChoiceNameClass.java58
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/ChoicePattern.java52
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/DataPattern.java59
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/Define.java51
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/ElementPattern.java52
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/EmptyPattern.java51
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/FullSyntaxBuilder.java1650
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/Grammar.java69
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/GrammarException.java56
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/GrammarValidator.java97
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/GroupPattern.java52
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/InterleavePattern.java52
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/ListPattern.java51
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/NSNameNameClass.java60
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/NameClass.java50
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/NameNameClass.java59
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/NotAllowedPattern.java51
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/OneOrMorePattern.java51
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/Param.java51
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/Pattern.java47
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/RELAXNGSchemaFactory.java163
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/RefPattern.java51
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/TextPattern.java51
-rw-r--r--libjava/classpath/gnu/xml/validation/relaxng/ValuePattern.java57
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/AnyAttribute.java66
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/AttributeDeclaration.java98
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/AttributeUse.java78
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/ComplexType.java101
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/ElementDeclaration.java124
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/Particle.java60
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/ValidationException.java57
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/XMLSchema.java133
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaAttributeTypeInfo.java98
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaBuilder.java839
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaElementTypeInfo.java91
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaSchemaFactory.java171
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaTypeInfo.java76
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaTypeInfoProvider.java81
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaValidator.java97
-rw-r--r--libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaValidatorHandler.java393
-rw-r--r--libjava/classpath/gnu/xml/xpath/AndExpr.java87
-rw-r--r--libjava/classpath/gnu/xml/xpath/ArithmeticExpr.java170
-rw-r--r--libjava/classpath/gnu/xml/xpath/BooleanFunction.java95
-rw-r--r--libjava/classpath/gnu/xml/xpath/CeilingFunction.java89
-rw-r--r--libjava/classpath/gnu/xml/xpath/ConcatFunction.java115
-rw-r--r--libjava/classpath/gnu/xml/xpath/Constant.java98
-rw-r--r--libjava/classpath/gnu/xml/xpath/ContainsFunction.java93
-rw-r--r--libjava/classpath/gnu/xml/xpath/CountFunction.java89
-rw-r--r--libjava/classpath/gnu/xml/xpath/DocumentOrderComparator.java57
-rw-r--r--libjava/classpath/gnu/xml/xpath/EqualityExpr.java274
-rw-r--r--libjava/classpath/gnu/xml/xpath/Expr.java549
-rw-r--r--libjava/classpath/gnu/xml/xpath/FalseFunction.java72
-rw-r--r--libjava/classpath/gnu/xml/xpath/FloorFunction.java90
-rw-r--r--libjava/classpath/gnu/xml/xpath/Function.java56
-rw-r--r--libjava/classpath/gnu/xml/xpath/FunctionCall.java169
-rw-r--r--libjava/classpath/gnu/xml/xpath/IdFunction.java103
-rw-r--r--libjava/classpath/gnu/xml/xpath/LangFunction.java123
-rw-r--r--libjava/classpath/gnu/xml/xpath/LastFunction.java73
-rw-r--r--libjava/classpath/gnu/xml/xpath/LocalNameFunction.java98
-rw-r--r--libjava/classpath/gnu/xml/xpath/NameFunction.java109
-rw-r--r--libjava/classpath/gnu/xml/xpath/NameTest.java143
-rw-r--r--libjava/classpath/gnu/xml/xpath/NamespaceTest.java120
-rw-r--r--libjava/classpath/gnu/xml/xpath/NamespaceUriFunction.java98
-rw-r--r--libjava/classpath/gnu/xml/xpath/NegativeExpr.java81
-rw-r--r--libjava/classpath/gnu/xml/xpath/NodeTypeTest.java141
-rw-r--r--libjava/classpath/gnu/xml/xpath/NormalizeSpaceFunction.java108
-rw-r--r--libjava/classpath/gnu/xml/xpath/NotFunction.java88
-rw-r--r--libjava/classpath/gnu/xml/xpath/NumberFunction.java103
-rw-r--r--libjava/classpath/gnu/xml/xpath/OrExpr.java87
-rw-r--r--libjava/classpath/gnu/xml/xpath/ParenthesizedExpr.java95
-rw-r--r--libjava/classpath/gnu/xml/xpath/Path.java54
-rw-r--r--libjava/classpath/gnu/xml/xpath/Pattern.java53
-rw-r--r--libjava/classpath/gnu/xml/xpath/PositionFunction.java73
-rw-r--r--libjava/classpath/gnu/xml/xpath/Predicate.java85
-rw-r--r--libjava/classpath/gnu/xml/xpath/RelationalExpr.java107
-rw-r--r--libjava/classpath/gnu/xml/xpath/Root.java91
-rw-r--r--libjava/classpath/gnu/xml/xpath/RoundFunction.java97
-rw-r--r--libjava/classpath/gnu/xml/xpath/Selector.java503
-rw-r--r--libjava/classpath/gnu/xml/xpath/StartsWithFunction.java92
-rw-r--r--libjava/classpath/gnu/xml/xpath/Steps.java260
-rw-r--r--libjava/classpath/gnu/xml/xpath/StringFunction.java119
-rw-r--r--libjava/classpath/gnu/xml/xpath/StringLengthFunction.java92
-rw-r--r--libjava/classpath/gnu/xml/xpath/SubstringAfterFunction.java98
-rw-r--r--libjava/classpath/gnu/xml/xpath/SubstringBeforeFunction.java97
-rw-r--r--libjava/classpath/gnu/xml/xpath/SubstringFunction.java119
-rw-r--r--libjava/classpath/gnu/xml/xpath/SumFunction.java104
-rw-r--r--libjava/classpath/gnu/xml/xpath/Test.java58
-rw-r--r--libjava/classpath/gnu/xml/xpath/TranslateFunction.java135
-rw-r--r--libjava/classpath/gnu/xml/xpath/TrueFunction.java72
-rw-r--r--libjava/classpath/gnu/xml/xpath/UnionExpr.java117
-rw-r--r--libjava/classpath/gnu/xml/xpath/VariableReference.java102
-rw-r--r--libjava/classpath/gnu/xml/xpath/XPathFactoryImpl.java90
-rw-r--r--libjava/classpath/gnu/xml/xpath/XPathImpl.java164
-rw-r--r--libjava/classpath/gnu/xml/xpath/XPathParser.java1475
-rw-r--r--libjava/classpath/gnu/xml/xpath/XPathParser.y794
-rw-r--r--libjava/classpath/gnu/xml/xpath/XPathTokenizer.java594
2179 files changed, 456082 insertions, 0 deletions
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 <code>fixed</code>.
+ * 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 <code>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 <code>fixed</code>, 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 <code>fixed</code> 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 <code>false</code>,
+ * 1 for <code>true</code>.
+ *
+ * @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 <code>fixed</code> 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 <code>len</code> bytes and
+ * will start storing them at position <code>off</code> 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 <code>false</code>. If the byte is non-zero, then
+ * the value returned is <code>true</code>.
+ * <p>
+ * This method can read a <code>boolean</code> written by an object
+ * implementing the <code>writeBoolean()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>boolean</code> 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.
+ * <p>
+ * This method can read a <code>byte</code> written by an object
+ * implementing the <code>writeByte()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>byte</code> 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 <code>char</code> value from an input stream.
+ * It operates by reading two bytes from the stream and converting them to
+ * a single 16-bit Java <code>char</code>. The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code>
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to a <code>char</code> in
+ * the following manner:
+ * <p>
+ * <code>(char)(((byte1 &amp; 0xFF) &lt;&lt; 8) | (byte2 &amp; 0xFF)</code>
+ * <p>
+ * This method can read a <code>char</code> written by an object
+ * implementing the <code>writeChar()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>char</code> 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 <code>long</code> value from the stream by calling the
+ * <code>readLong()</code> method in this interface, then converts
+ * that <code>long</code> to a <code>double</code> using the
+ * <code>longBitsToDouble</code> method in the class
+ * <code>java.lang.Double</code>
+ * <p>
+ * This method can read a <code>double</code> written by an object
+ * implementing the <code>writeDouble()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>double</code> 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 <code>int</code> value from the
+ * stream by calling the <code>readInt()</code> method in this
+ * interface, then converts that <code>int</code> to a
+ * <code>float</code> using the <code>intBitsToFloat</code> method
+ * in the class <code>java.lang.Float</code>
+ * <p>
+ * This method can read a <code>float</code> written by an object
+ * implementing the <code>writeFloat()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>float</code> 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 <code>int</code> value from an input stream
+ * It operates by reading four bytes from the stream and converting them to
+ * a single Java <code>int</code>. The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> through <code>byte4</code> represent
+ * the first four bytes read from the stream, they will be
+ * transformed to an <code>int</code> in the following manner:
+ * <p>
+ * <code>(int)(((byte1 &amp; 0xFF) &lt;&lt; 24) + ((byte2 &amp; 0xFF) &lt;&lt; 16) +
+ * ((byte3 &amp; 0xFF)&lt;&lt; 8) + (byte4 &amp; 0xFF)))</code>
+ * <p>
+ * The value returned is in the range of -2147483648 to 2147483647.
+ * <p>
+ * This method can read an <code>int</code> written by an object
+ * implementing the <code>writeInt()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>int</code> 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 <code>long</code> value from an input stream
+ * It operates by reading eight bytes from the stream and converting them to
+ * a single Java <code>long</code>. The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> through <code>byte8</code> represent
+ * the first eight bytes read from the stream, they will be
+ * transformed to an <code>long</code> in the following manner:
+ * <p>
+ * <code>(long)(((byte1 &amp; 0xFF) &lt;&lt; 56) + ((byte2 &amp; 0xFF) &lt;&lt; 48) +
+ * ((byte3 &amp; 0xFF) &lt;&lt; 40) + ((byte4 &amp; 0xFF) &lt;&lt; 32) +
+ * ((byte5 &amp; 0xFF) &lt;&lt; 24) + ((byte6 &amp; 0xFF) &lt;&lt; 16) +
+ * ((byte7 &amp; 0xFF) &lt;&lt; 8) + (byte8 &amp; 0xFF)))
+ * </code>
+ * <p>
+ * The value returned is in the range of -9223372036854775808 to
+ * 9223372036854775807.
+ * <p>
+ * This method can read an <code>long</code> written by an object
+ * implementing the <code>writeLong()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>long</code> 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 <code>short</code>. The
+ * two bytes are stored most significant byte first (i.e., "big
+ * endian") regardless of the native host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code>
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to a <code>short</code>. in
+ * the following manner:
+ * <p>
+ * <code>(short)(((byte1 &amp; 0xFF) &lt;&lt; 8) | (byte2 &amp; 0xFF))</code>
+ * <p>
+ * The value returned is in the range of -32768 to 32767.
+ * <p>
+ * This method can read a <code>short</code> written by an object
+ * implementing the <code>writeShort()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>short</code> 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 <code>int</code>
+ * value from the stream. The value returned is in the range of 0 to
+ * 255.
+ * <p>
+ * This method can read an unsigned byte written by an object
+ * implementing the <code>writeUnsignedByte()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The unsigned bytes value read as a Java <code>int</code>.
+ *
+ * @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 <code>int</code> The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code>
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to an <code>int</code> in
+ * the following manner:
+ * <p>
+ * <code>(int)(((byte1 &amp; 0xFF) &lt;&lt; 8) + (byte2 &amp; 0xFF))</code>
+ * <p>
+ * The value returned is in the range of 0 to 65535.
+ * <p>
+ * This method can read an unsigned short written by an object
+ * implementing the <code>writeUnsignedShort()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The unsigned short value read as a Java <code>int</code>
+ *
+ * @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 <code>int</code>)
+ * to the underlying output stream.
+ *
+ * @param value The <code>byte</code> to write, passed as an <code>int</code>.
+ *
+ * @exception IOException If an error occurs.
+ */
+ void write(int value)
+ throws IOException;
+
+ /**
+ * This method writes <code>len</code> bytes from the specified byte array
+ * <code>buf</code> starting at position <code>offset</code> 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
+ * <code>value</code> is <code>true</code>, 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 <code>readBoolean</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The <code>boolean</code> 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
+ * <code>int</code> value passed.
+ *
+ * The value written can be read using the <code>readByte</code> or
+ * <code>readUnsignedByte</code> methods in <code>DataInput</code>.
+ *
+ * @param value The <code>byte</code> to write to the stream, passed as
+ * the low eight bits of an <code>int</code>.
+ *
+ * @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 <code>int</code>
+ * 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 <code>int</code>
+ * 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 <code>int</code> 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 <code>long</code> value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ */
+ void writeLong(long value)
+ throws IOException;
+
+ /**
+ * This method writes a Java <code>float</code> value to the stream.
+ * @param value The <code>float</code> value to write to the stream
+ *
+ * @exception IOException If an error occurs
+ */
+ void writeFloat(float value)
+ throws IOException;
+
+ /**
+ * This method writes a Java <code>double</code> value to the stream.
+ *
+ * @param value The <code>double</code> 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 <code>DataInputStream</code>
+ * to read from the specified subordinate stream.
+ *
+ * @param in The subordinate <code>InputStream</code> 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 <code>len</code> bytes and
+ * will start storing them at position <code>off</code> 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 <code>false</code>. If the byte is non-zero, then
+ * the value returned is <code>true</code>.
+ * <p>
+ * This method can read a <code>boolean</code> written by an object
+ * implementing the <code>writeBoolean()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>boolean</code> 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.
+ * <p>
+ * This method can read a <code>byte</code> written by an object
+ * implementing the <code>writeByte()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>byte</code> 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 <code>char</code> value from an input stream.
+ * It operates by reading two bytes from the stream and converting them to
+ * a single 16-bit Java <code>char</code>. The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code>
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to a <code>char</code> in
+ * the following manner:
+ * <p>
+ * <code>(char)(((byte1 &amp; 0xFF) &lt;&lt; 8) | (byte2 &amp; 0xFF)</code>
+ * <p>
+ * This method can read a <code>char</code> written by an object
+ * implementing the <code>writeChar()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>char</code> 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 <code>long</code> value from the stream by calling the
+ * <code>readLong()</code> method in this interface, then converts
+ * that <code>long</code> to a <code>double</code> using the
+ * <code>longBitsToDouble</code> method in the class
+ * <code>java.lang.Double</code>
+ * <p>
+ * This method can read a <code>double</code> written by an object
+ * implementing the <code>writeDouble()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>double</code> 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 <code>int</code> value from the
+ * stream by calling the <code>readInt()</code> method in this
+ * interface, then converts that <code>int</code> to a
+ * <code>float</code> using the <code>intBitsToFloat</code> method
+ * in the class <code>java.lang.Float</code>
+ * <p>
+ * This method can read a <code>float</code> written by an object
+ * implementing the <code>writeFloat()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>float</code> 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 <code>buf</code>
+ * starting
+ * <code>offset</code> bytes into the buffer. The number of bytes read
+ * will be
+ * exactly <code>len</code>. 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 <code>len</code> 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 <code>int</code> value from an input stream
+ * It operates by reading four bytes from the stream and converting them to
+ * a single Java <code>int</code>. The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> through <code>byte4</code> represent
+ * the first four bytes read from the stream, they will be
+ * transformed to an <code>int</code> in the following manner:
+ * <p>
+ * <code>(int)(((byte1 &amp; 0xFF) &lt;&lt; 24) + ((byte2 &amp; 0xFF) &lt;&lt; 16) +
+ * ((byte3 &amp; 0xFF)&lt;&lt; 8) + (byte4 &amp; 0xFF)))</code>
+ * <p>
+ * The value returned is in the range of -2147483648 to 2147483647.
+ * <p>
+ * This method can read an <code>int</code> written by an object
+ * implementing the <code>writeInt()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>int</code> 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 <code>char</code> values by treating the byte read as the low
+ * eight bits of the <code>char</code> and using 0 as the high eight
+ * bits. Because of this, it does not support the full 16-bit
+ * Unicode character set.
+ * <p>
+ * 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
+ * <code>String</code> A line terminator is a byte sequence
+ * consisting of either <code>\r</code>, <code>\n</code> or
+ * <code>\r\n</code>. These termination charaters are discarded and
+ * are not returned as part of the string.
+ * <p>
+ * This method can read data that was written by an object implementing the
+ * <code>writeLine()</code> method in <code>DataOutput</code>.
+ *
+ * @return The line read as a <code>String</code>
+ *
+ * @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 <code>long</code> value from an input stream
+ * It operates by reading eight bytes from the stream and converting them to
+ * a single Java <code>long</code>. The bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> through <code>byte8</code> represent
+ * the first eight bytes read from the stream, they will be
+ * transformed to an <code>long</code> in the following manner:
+ * <p>
+ * <code>(long)(((byte1 &amp; 0xFF) &lt;&lt; 56) + ((byte2 &amp; 0xFF) &lt;&lt; 48) +
+ * ((byte3 &amp; 0xFF) &lt;&lt; 40) + ((byte4 &amp; 0xFF) &lt;&lt; 32) +
+ * ((byte5 &amp; 0xFF) &lt;&lt; 24) + ((byte6 &amp; 0xFF) &lt;&lt; 16) +
+ * ((byte7 &amp; 0xFF) &lt;&lt; 8) + (byte8 &amp; 0xFF)))
+ * </code>
+ * <p>
+ * The value returned is in the range of -9223372036854775808 to
+ * 9223372036854775807.
+ * <p>
+ * This method can read an <code>long</code> written by an object
+ * implementing the <code>writeLong()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>long</code> 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 <code>short</code>. The
+ * two bytes are stored most significant byte first (i.e., "big
+ * endian") regardless of the native host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code>
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to a <code>short</code>. in
+ * the following manner:
+ * <p>
+ * <code>(short)(((byte1 &amp; 0xFF) &lt;&lt; 8) | (byte2 &amp; 0xFF))</code>
+ * <p>
+ * The value returned is in the range of -32768 to 32767.
+ * <p>
+ * This method can read a <code>short</code> written by an object
+ * implementing the <code>writeShort()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The <code>short</code> 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 <code>int</code>
+ * value from the stream. The value returned is in the range of 0 to
+ * 255.
+ * <p>
+ * This method can read an unsigned byte written by an object
+ * implementing the <code>writeUnsignedByte()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The unsigned bytes value read as a Java <code>int</code>.
+ *
+ * @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 <code>int</code> The two bytes are stored most
+ * significant byte first (i.e., "big endian") regardless of the native
+ * host byte ordering.
+ * <p>
+ * As an example, if <code>byte1</code> and <code>byte2</code>
+ * represent the first and second byte read from the stream
+ * respectively, they will be transformed to an <code>int</code> in
+ * the following manner:
+ * <p>
+ * <code>(int)(((byte1 &amp; 0xFF) &lt;&lt; 8) + (byte2 &amp; 0xFF))</code>
+ * <p>
+ * The value returned is in the range of 0 to 65535.
+ * <p>
+ * This method can read an unsigned short written by an object
+ * implementing the <code>writeUnsignedShort()</code> method in the
+ * <code>DataOutput</code> interface.
+ *
+ * @return The unsigned short value read as a Java <code>int</code>
+ *
+ * @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 <code>DataOutputStream</code> to
+ * write its data to the specified underlying <code>OutputStream</code>
+ *
+ * @param out The subordinate <code>OutputStream</code> 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 <code>int</code>)
+ * to the underlying output stream.
+ *
+ * @param value The <code>byte</code> to write, passed as an <code>int</code>.
+ *
+ * @exception IOException If an error occurs.
+ */
+ public synchronized void write(int value)
+ throws IOException
+ {
+ out.write(value);
+ }
+
+ /**
+ * This method writes <code>len</code> bytes from the specified byte array
+ * <code>buf</code> starting at position <code>offset</code> 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
+ * <code>value</code> is <code>true</code>, 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 <code>readBoolean</code>
+ * method in <code>DataInput</code>.
+ *
+ * @param value The <code>boolean</code> 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
+ * <code>int</code> value passed.
+ *
+ * The value written can be read using the <code>readByte</code> or
+ * <code>readUnsignedByte</code> methods in <code>DataInput</code>.
+ *
+ * @param value The <code>byte</code> to write to the stream, passed as
+ * the low eight bits of an <code>int</code>.
+ *
+ * @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 <code>short</code> value to write to the stream,
+ * passed as an <code>int</code>.
+ *
+ * @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 <code>float</code> value to the stream. This
+ * value is written by first calling the method
+ * <code>Float.floatToIntBits</code>
+ * to retrieve an <code>int</code> representing the floating point number,
+ * then writing this <code>int</code> value to the stream exactly the same
+ * as the <code>writeInt()</code> method does.
+ *
+ * @param value The <code>float</code> 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 <code>double</code> value to the stream. This
+ * value is written by first calling the method
+ * <code>Double.doubleToLongBits</code>
+ * to retrieve an <code>long</code> representing the floating point number,
+ * then writing this <code>long</code> value to the stream exactly the same
+ * as the <code>writeLong()</code> method does.
+ *
+ * @param value The <code>double</code> 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[] { "<message unavailable>" });
+ }
+ }
+ 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 <code>null</code> value.
+ */
+ public DuplicateNameHolder()
+ {
+ }
+
+ /**
+ * Create the initialised instance.
+ * @param initialValue the value that will be assigned to
+ * the <code>value</code> 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
+ * <code>null</code>
+ */
+ 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 <code>null</code> 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 <code>null</code>.
+ *
+ * @return <code>null</code>, 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 <code>fixed</code>. 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 <code>fixed</code> 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 <code>adis</code>.
+ 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 <code>DynAny</code>.
+ */
+ public DynAny[] value;
+
+ /**
+ * Create the unitialised instance, leaving the value array
+ * with default <code>null</code> value.
+ */
+ public DynAnySeqHolder()
+ {
+ }
+
+ /**
+ * Create the initialised instance.
+ * @param initialValue the array that will be assigned to
+ * the <code>value</code> 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
+ * <code>null</code> value.
+ */
+ public ForwardRequestHolder()
+ {
+ }
+
+ /**
+ * Create the initialised instance.
+ *
+ * @param initialValue the value that will be assigned to the
+ * <code>value</code> 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 <code>null</code> value.
+ */
+ public NameDynAnyPairHolder()
+ {
+ }
+
+ /**
+ * Create the initialised instance.
+ * @param initialValue the value that will be assigned to
+ * the <code>value</code> 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 <code>NameDynAnyPair</code>.
+ */
+ public NameDynAnyPair[] value;
+
+ /**
+ * Create the unitialised instance, leaving the value array
+ * with default <code>null</code> value.
+ */
+ public NameDynAnyPairSeqHolder()
+ {
+ }
+
+ /**
+ * Create the initialised instance.
+ * @param initialValue the array that will be assigned to
+ * the <code>value</code> 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 <code>null</code> value.
+ */
+ public NameValuePairHolder()
+ {
+ }
+
+ /**
+ * Create the initialised instance.
+ * @param initialValue the value that will be assigned to
+ * the <code>value</code> 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 <code>NameValuePair</code>.
+ */
+ public NameValuePair[] value;
+
+ /**
+ * Create the unitialised instance, leaving the value array
+ * with default <code>null</code> value.
+ */
+ public NameValuePairSeqHolder()
+ {
+ }
+
+ /**
+ * Create the initialised instance.
+ * @param initialValue the array that will be assigned to
+ * the <code>value</code> 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: <br>
+ * 1. corbaloc:[iiop][version.subversion@]:host[:port]/key <br>
+ * 2. corbaloc:rir:[/key] <br>
+ * 3. corbaname:[iiop][version.subversion@]:host[:port]/key <br>
+ * 4. corbaname:rir:[/key] <br>
+ * 5. file://[file name]<br>
+ * 6. http://[url]<br>
+ * 7. ftp://[url]<br>
+ *
+ * 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 <i>tnameserv</i> and persistent <i>orbd</i>.
+ *
+ * @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 <code>octet</code> that is mapped into
+ * java <code>long</code>.
+ *
+ * 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 <code>long</code> (CORBA <code>octet</code>) value,
+ * held by this OctetHolder.
+ */
+ public byte value;
+
+ /**
+ * Constructs an instance of OctetHolder,
+ * initializing {@link #value} to <code>0 </code>.
+ */
+ public OctetHolder()
+ {
+ }
+
+ /**
+ * Constructs an instance of OctetHolder,
+ * initializing {@link #value} to the given <code>octed</code> (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 <code>octet</code>, 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 <code>octet</code>, 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 <code>null</code>.
+ */
+ 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
+ * <code>main(String[] args)</code> 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 <code>null</code>.
+ */
+ 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
+ * <code>offset</code> 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 <code>null</code> value.
+ */
+ public ForwardRequestHolder()
+ {
+ }
+
+ /**
+ * Create the initialised instance.
+ * @param initialValue the value that will be assigned to
+ * the <code>value</code> 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 <code>null</code> value.
+ */
+ public InvalidPolicyHolder()
+ {
+ }
+
+ /**
+ * Create the initialised instance.
+ * @param initialValue the value that will be assigned to
+ * the <code>value</code> 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 <code>this</code>.
+ */
+ 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
+ * <code>this</code> 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) <code>activate_id</code> = 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);
+ }
+
+ /**
+ * <p>
+ * Create the object reference, encapsulating the given repository Id and
+ * the given Object Id. The returned object will <i>not</i> 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 <i>not</i> 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.
+ * <ul>
+ * <li>If the POA has both the RETAIN and the UNIQUE_ID policy and the
+ * specified servant is active, the method return the Object Id associated
+ * with that servant. </li>
+ * <li> If the POA has both the RETAIN and the IMPLICIT_ACTIVATION policy and
+ * either the POA has the MULTIPLE_ID policy or the specified servant is
+ * inactive, the method activates the servant using a POA-generated Object Id
+ * and the Interface Id associated with the servant, and returns that Object
+ * Id. </li>
+ * <li>If the POA has the USE_DEFAULT_SERVANT policy, the servant specified
+ * is the default servant, and the method is being invoked in the context of
+ * executing a request on the default servant, the method returns the ObjectId
+ * associated with the current invocation. </li>
+ * </ul>
+ *
+ * @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."
+ );
+ }
+
+ /**
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @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 <code>null</code> 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);
+ }
+
+ /**
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * The remote invocation on the target, belonging to the POA that is currently
+ * destroyed return the remote exception ({@link TRANSIENT}, minor code 4).
+ * </p>
+ *
+ * @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 <i>active</i>
+ * object in the Active Object Map. This method should not try to access POA
+ * being destroyed. If <code>destroy</code> 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 <i>new</i> 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 <code>char</code> that is mapped into
+ * java <code>char</code>.
+ *
+ * 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 <code>char</code> (CORBA <code>wchar</code>) value,
+ * held by this WCharHolder.
+ */
+ public char value;
+
+ /**
+ * Constructs an instance of WCharHolder,
+ * initializing {@link #value} to <code>0 </code>.
+ */
+ public WCharHolder()
+ {
+ }
+
+ /**
+ * Constructs an instance of WCharHolder,
+ * initializing {@link #value} to the given <code>char</code>.
+ *
+ * @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 <code>char</code>, 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 <code>char</code>, 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 <code>wstring</code> that is mapped into
+ * java <code>String</code>. 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 <code>String</code> (CORBA <code>string</code>) value,
+ * held by this WStringHolder.
+ */
+ public String value;
+
+ /**
+ * Constructs an instance of WStringHolder,
+ * initializing {@link #value} to <code>null</code>.
+ */
+ public WStringHolder()
+ {
+ }
+
+ /**
+ * Constructs an instance of WStringHolder,
+ * initializing {@link #value} to the given <code>String</code>.
+ *
+ * @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 <code>string</code>, 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 <code>string</code>, 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
+ * <code>this</code> can be returned.
+ *
+ * @return <code>this</code>
+ */
+ 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 <code>Principal</code>/
+ * @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 <code>fixed</code>/
+ * @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 <code>fixed</code>, 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 <code>fixed</code>, 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html -
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.CORBA.interfaces</title></head>
+
+<body>
+<p>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</p>
+</body>
+</html>
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 <code>other</code> 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
+ * <code>IDL:omg.org/CORBA/ {type name} Seq:1.0</code>.
+ *
+ * @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 <code>fixed</code>
+ * @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 <code>TCKind.t_..</code> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.CORBA.typecodes</title></head>
+
+<body>
+ Contains GNU Classpath specific typecode definitions.
+
+ @author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)
+</body>
+</html>
+
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 <code>true</code> 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 <code>false</code>.
+ */
+ 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<A,B>
+{
+
+ /**
+ * 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<A,B> p = (Pair<A,B>) 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.
+ *
+ * <p>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.
+ *
+ * <p>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 <code>META-INF/services</code>. 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.
+ *
+ * <p><b>Example</b>
+ *
+ * <p>For example, a JAR might provide two implementations of the
+ * service provider interface <code>org.foo.ThinkService</code>,
+ * namely <code>com.acme.QuickThinker</code> and
+ * <code>com.acme.DeepThinker</code>. The code for <code>QuickThinker</code>
+ * woud look as follows:
+ *
+ * <pre>
+ * package com.acme;
+ *
+ * &#x2f;**
+ * * Provices a super-quick, but not very deep implementation of ThinkService.
+ * *&#x2f;
+ * public class QuickThinker
+ * implements org.foo.ThinkService
+ * {
+ * &#x2f;**
+ * * 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.
+ * *
+ * * &lt;p&gt;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.
+ * *&#x2f;
+ * public QuickThinker()
+ * {
+ * }
+ *
+ * &#x2f;**
+ * * Returns the speed of this ThinkService in thoughts per second.
+ * * Applications can choose among the available service providers
+ * * based on this value.
+ * *&#x2f;
+ * public double getSpeed()
+ * {
+ * return 314159.2654;
+ * }
+ *
+ * &#x2f;**
+ * * Produces a thought. While the returned thoughts are not very
+ * * deep, they are generated in very short time.
+ * *&#x2f;
+ * public Thought think()
+ * {
+ * return null;
+ * }
+ * }
+ * </pre>
+ *
+ * <p>The code for <code>com.acme.DeepThinker</code> is left as an
+ * exercise to the reader.
+ *
+ * <p>Acme&#x2019;s <code>ThinkService</code> plug-in gets deployed as
+ * a JAR file. Besides the bytecode and resources for
+ * <code>QuickThinker</code> and <code>DeepThinker</code>, it also
+ * contains the text file
+ * <code>META-INF/services/org.foo.ThinkService</code>:
+ *
+ * <pre>
+ * # Available implementations of org.foo.ThinkService
+ * com.acme.QuickThinker
+ * com.acme.DeepThinker
+ * </pre>
+ *
+ * <p><b>Thread Safety</b>
+ *
+ * <p>It is safe to use <code>ServiceFactory</code> from multiple
+ * concurrent threads without external synchronization.
+ *
+ * <p><b>Note for User Applications</b>
+ *
+ * <p>User applications that want to load plug-ins should not directly
+ * use <code>gnu.classpath.ServiceFactory</code>, 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 <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a>
+ */
+public final class ServiceFactory
+{
+ /**
+ * A logger that gets informed when a service gets loaded, or
+ * when there is a problem with loading a service.
+ *
+ * <p>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.
+ *
+ * <p><b>On-demand loading:</b> 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.
+ *
+ * <p><b>Security considerations:</b> Any loaded service providers
+ * are loaded through the specified ClassLoader, or the system
+ * ClassLoader if <code>classLoader</code> is
+ * <code>null</code>. When <code>lookupProviders</code> is called,
+ * the current {@link AccessControlContext} gets recorded. This
+ * captured security context will determine the permissions when
+ * services get loaded via the <code>next()</code> method of the
+ * returned <code>Iterator</code>.
+ *
+ * @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 <code>null</code> for the system class
+ * loader. For using the context class loader, see {@link
+ * #lookupProviders(Class)}.
+ *
+ * @return an iterator over instances of <code>spi</code>.
+ *
+ * @throws IllegalArgumentException if <code>spi</code> is
+ * <code>null</code>.
+ */
+ public static <P> Iterator<P> lookupProviders(Class<P> spi,
+ ClassLoader loader)
+ {
+ return lookupProviders(spi, loader, false);
+ }
+
+ /**
+ * Finds service providers that are implementing the specified
+ * Service Provider Interface.
+ *
+ * <p><b>On-demand loading:</b> 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.
+ *
+ * <p><b>Security considerations:</b> Any loaded service providers
+ * are loaded through the specified ClassLoader, or the system
+ * ClassLoader if <code>classLoader</code> is
+ * <code>null</code>. When <code>lookupProviders</code> is called,
+ * the current {@link AccessControlContext} gets recorded. This
+ * captured security context will determine the permissions when
+ * services get loaded via the <code>next()</code> method of the
+ * returned <code>Iterator</code>.
+ *
+ * @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 <code>null</code> 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 <code>spi</code>.
+ *
+ * @throws IllegalArgumentException if <code>spi</code> is
+ * <code>null</code>.
+ */
+ public static <P> Iterator<P> lookupProviders(Class<P> spi,
+ ClassLoader loader,
+ boolean error)
+ {
+ String resourceName;
+ Enumeration<URL> 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<P> empty = Collections.emptyList();
+ return empty.iterator();
+ }
+ }
+
+ return new ServiceIterator<P>(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 <code>spi</code>.
+ *
+ * @throws IllegalArgumentException if <code>spi</code> is
+ * <code>null</code>.
+ *
+ * @see #lookupProviders(Class, ClassLoader)
+ */
+ public static <P> Iterator<P> lookupProviders(Class<P> 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 <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a>
+ */
+ private static final class ServiceIterator<P>
+ implements Iterator<P>
+ {
+ /**
+ * The service provider interface (usually an interface, sometimes
+ * an abstract class) which the services must implement.
+ */
+ private final Class<P> spi;
+
+
+ /**
+ * An Enumeration<URL> over the URLs that contain a resource
+ * <code>META-INF/services/&lt;org.foo.SomeService&gt;</code>,
+ * as returned by {@link ClassLoader#getResources(String)}.
+ */
+ private final Enumeration<URL> 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 <code>null</code> 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 <code>null</code> 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<URL> over the URLs that contain a
+ * resource
+ * <code>META-INF/services/&lt;org.foo.SomeService&gt;</code>, 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<P> spi, Enumeration<URL> 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
+ * <code>false</code>.
+ */
+ 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<P>(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 <code>java.util.logging</code>
+ * 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 <code>&#x201c;Could not
+ * load {0}.&#x201d;</code>
+ *
+ * @param param the parameter(s) for the log message, or
+ * <code>null</code> if <code>msg</code> does not specify any
+ * parameters. If <code>param</code> is not an array, an array with
+ * <code>param</code> as its single element gets passed to the
+ * logging framework.
+ *
+ * @param t a Throwable that is associated with the log record, or
+ * <code>null</code> 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.
+ *
+ * <p>Class loading and instantiation is encapsulated in a
+ * <code>PriviledgedAction</code> in order to restrict the loaded
+ * service providers to the {@link java.security.AccessControlContext}
+ * that was active when {@link
+ * gnu.classpath.ServiceFactory#lookupProviders(Class, ClassLoader)} was
+ * called, even though the actual loading is delayed to the time when the
+ * provider is actually needed.
+ *
+ * @author <a href="mailto:brawer@dandelis.ch">Sascha Brawer</a>
+ */
+final class ServiceProviderLoadingAction<P>
+ implements PrivilegedExceptionAction<P>
+{
+ /**
+ * 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<P> 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 <code>spi</code>,
+ * <code>providerName</code> or <code>loader</code> is
+ * <code>null</code>.
+ */
+ ServiceProviderLoadingAction(Class<P> 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
+ * <code>providerName</code> to the constructor.
+ *
+ * @throws ClassCastException if the service provider does not
+ * implement the <code>spi</code> interface that was passed to the
+ * constructor.
+ *
+ * @throws IllegalAccessException if the service provider class or
+ * its no-argument constructor are not <code>public</code>.
+ *
+ * @throws InstantiationException if the service provider class is
+ * <code>abstract</code>, 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<P> loadedClass;
+ P serviceProvider;
+
+ loadedClass = (Class<P>) 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 <code>setProperties(null)</code>.
+ */
+ 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.
+ * <p>
+ * The fixed format of this formatter is as follows:
+ * <p>
+ * <ol>
+ * <li>Date: As a yyyy-MM-dd string.</li>
+ * <li>Time: As a HH:mm:ss.SSSS Z string.</li>
+ * <li>Thread identifier, right-justified, and framed in an 11-digit field.</li>
+ * <li>Class name, without its package name, left-justified, and framed in a
+ * 32-character field.</li>
+ * <li>Method name, left-justified, and framed in a 32-character field.</li>
+ * <li>Level name, left-justified, and framed in a 6-character field.</li>
+ * <li>User message and arguments.</li>
+ * <li>Platform-dependent line-separator.</li>
+ * <li>Optionally, if the log-record contains a thrown exception, that
+ * exception's stack trace is appended to the output.</li>
+ * </ol>
+ * <p>
+ * Here is an example of the output generated by this formatter:
+ * <p>
+ * <pre>
+ * 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.<init> (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
+ * </pre>
+ */
+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=<boolean>)
+ 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
+ * <code>canUnrestrictedlyRedefineClasses</code> 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 <code>canUnrestrictedlyRedefineClasses</code>
+ * 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
+ * <code>canUnrestrictedlyRedefineClasses</code> 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
+ * <code>canUnrestrictedlyRedefineClasses</code> 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,
+ * <code>java.lang.Integer.TYPE</code>)." -- 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 <code>ClassPrepareEvent</code>
+ *
+ * @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 <code>null</code>
+ */
+ 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 <code>ClassUnloadEvent</code>
+ *
+ * @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 <code>null</code>
+ */
+ 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 <code>Event</code> 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 <code>ThreadId.class</code> should return a
+ * <code>Thread</code>.
+ *
+ * @param type the type of parameter to return
+ * @returns the parameter (not the ID) or <code>null</code> 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 <code>JdwpPacket</code> 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, <code>EventManager</code> 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 <code>EventManager</code> 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 <code>EventManager</code>
+ 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 <code>EventManager</code> is handling event filtering.
+ *
+ * @param event the event
+ * @return requests that are interested in this event
+ * or <code>null</code> 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 <code>null</code> 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 <code>Collection</code> 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. <code>EventRequest</code>s 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 <code>EventRequest</code>
+ *
+ * @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 <code>EventRequest</code> 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 <code>ExceptionEvent</code> 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 <code>MethodEntryEvent</code>
+ *
+ * @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 <code>MethodExitEvent</code>
+ *
+ * @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 <code>SingleStepEvent</code>
+ *
+ * @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.
+ *
+ * <p>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 <code>ThreadEndEvent</code>
+ *
+ * @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 <code>null</code>
+ */
+ 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.
+ *
+ * <p>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 <code>null</code>
+ */
+ 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 <code>null</code>
+ */
+ 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 <code>VmInitEvent</code> 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 <code>null</code>
+ */
+ 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 <code>ClassExcludeFilter</code>
+ *
+ * @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 <code>Event</code> 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 <code>ClassMatchFilter</code>
+ *
+ * @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 <code>Event</code> 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 <code>ClassOnlyFilter</code>
+ *
+ * @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 <code>Event</code> 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 <code>ConditionalFilter</code> with the
+ * given conditional.
+ *
+ * <p><b>NOTE:</b> 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 <code>Event</code> 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 <code>CountFilter</code> 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 <code>Event</code> 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 (<code>null</code> for all)
+ *
+ * @return the class's ID
+ */
+ public ReferenceTypeId getType ()
+ {
+ return _refId;
+ }
+
+
+ /**
+ * Does the given event match the filter?
+ *
+ * @param event the <code>Event</code> 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 <code>FieldOnlyFilter</code>.
+ *
+ * @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 <code>Event</code> 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.
+ *
+ * <p>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.
+ *
+ * <p>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 <code>Event</code> 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 <code>InstanceOnlyFilter</code>.
+ *
+ * @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 <code>Event</code> 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 <code>LocationOnlyFilter</code>.
+ *
+ * @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 <code>Event</code> 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 <code>Event</code> 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 <code>ThreadOnlyFilter</code> 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 <code>Event</code> 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 <code>JdwpException</code> 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 <code>JdwpException</code> 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 <code>JdwpIllegalArgumentException</code> 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 <keiths@redhat.com>
+ */
+public class ArrayId
+ extends ObjectId
+{
+ // Arrays are handled a little differently than other IDs
+ //public static final Class typeClass = UNDEFINED
+
+ /**
+ * Constructs a new <code>ArrayId</code>
+ */
+ 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 <keiths@redhat.com>
+ */
+public class ArrayReferenceTypeId
+ extends ReferenceTypeId
+{
+ /**
+ * Constructs a new <code>ArrayReferenceTypeId</code>
+ */
+ 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 <keiths@redhat.com>
+ */
+public class ClassLoaderId
+ extends ObjectId
+{
+ /**
+ * The object class that this id represents
+ */
+ public static final Class typeClass = ClassLoader.class;
+
+ /**
+ * Constructs a new <code>ClassLoaderId</code>
+ */
+ 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 <keiths@redhat.com>
+ */
+public class ClassObjectId
+ extends ObjectId
+{
+ /**
+ * The object class that this id represents
+ */
+ public static final Class typeClass = Class.class;
+
+ /**
+ * Constructs a new <code>ClassObjectId</code>
+ */
+ 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 <keiths@redhat.com>
+ */
+public class ClassReferenceTypeId
+ extends ReferenceTypeId
+{
+ /**
+ * Constructs a new <code>ClassReferenceTypeId</code>
+ */
+ 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 <keiths@redhat.com>
+ */
+public class InterfaceReferenceTypeId
+ extends ReferenceTypeId
+{
+ /**
+ * Constructs a new <code>InterfaceReferenceTypeId</code>
+ */
+ 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 <keiths@redhat.com>
+ */
+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 <code>JdwpId</code>
+ */
+ 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 <code>DataOutputStream</code>
+ * @param outStream the <code>DataOutputStream</code> to use
+ * @throws IOException when an error occurs on the <code>OutputStream</code>
+ */
+ 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 <code>DataOutputStream</code> to use
+ * @throws IOException when an error occurs on the <code>OutputStream</code>
+ */
+ 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 <kgallowa@redhat.com>
+ */
+public class NullObjectId
+ extends ObjectId
+{
+ /**
+ * The object class that this id represents
+ */
+ public static final Class typeClass = NullObject.class;
+
+ /**
+ * Constructs a new <code>NullObjectId</code>
+ */
+ public NullObjectId()
+ {
+ super();
+ setId((long) 0);
+ _reference = new SoftReference<NullObject>(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 <keiths@redhat.com>
+ */
+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 <code>ObjectId</code>
+ */
+ public ObjectId ()
+ {
+ super (JdwpConstants.Tag.OBJECT);
+ }
+
+ /**
+ * Constructs a new <code>ObjectId</code> 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 <code>OutputStream</code>
+ */
+ 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
+ * <code>JdwpId</code>'s tag member for its own use (type tag).
+ *
+ * @author Keith Seitz <keiths@redhat.com>
+ */
+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 <keiths@redhat.com>
+ */
+public class StringId
+ extends ObjectId
+{
+ /**
+ * The object class that this id represents
+ */
+ public static final Class typeClass = String.class;
+
+ /**
+ * Constructs a new <code>StringId</code>
+ */
+ 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 <keiths@redhat.com>
+ */
+public class ThreadGroupId
+ extends ObjectId
+{
+ /**
+ * The object class that this id represents
+ */
+ public static final Class typeClass = ThreadGroup.class;
+
+ /**
+ * Constructs a new <code>ThreadGroupId</code>
+ */
+ 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 <keiths@redhat.com>
+ */
+public class ThreadId
+ extends ObjectId
+{
+ /**
+ * The object class that this id represents
+ */
+ public static final Class typeClass = Thread.class;
+
+ /**
+ * Constructs a new <code>ThreadId</code>
+ */
+ 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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <code>PacketProcessor</code> 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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <keiths@redhat.com>
+ */
+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 <code>JdwpCommandPacket</code>
+ */
+ public JdwpCommandPacket ()
+ {
+ // Don't assign an id. This constructor is called by
+ // JdwpPacket.fromBytes, and that will assign a packet id.
+ }
+
+ /**
+ * Constructs a new <code>JdwpCommandPacket</code>
+ * 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.
+ *
+ * <p>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 <code>JdwpConnection</code> 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 <code>getPacket</code>
+ */
+ 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 <code>JdwpPacket</code> ready for processing
+ * <code>null</code> 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 <code>JdwpPacket</code> 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 <keiths@redhat.com>
+ */
+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 <code>JdwpPacket</code> 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 <code>bytes</code> to start processing
+ * @return number of bytes in <code>bytes</code> processed
+ */
+ protected abstract int myFromBytes (byte[] bytes, int index);
+
+ /**
+ * Convert the given bytes into a <code>JdwpPacket</code>. Uses the
+ * abstract method <code>myFromBytes</code> to allow subclasses to
+ * process data.
+ *
+ * If the given data does not represent a valid JDWP packet, it returns
+ * <code>null</code>.
+ *
+ * @param bytes packet data from the wire
+ * @return number of bytes in <code>bytes</code> 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 <keiths@redhat.com>
+ */
+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 <code>JdwpReplyPacket</code>.
+ */
+ 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 <code>JdwpReplyPacket</code> 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 <code>JdwpReplyPacket</code> 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 <code>InputStream</code> 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 <code>OutputStream</code> 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 <keiths@redhat.com>
+ */
+public class TransportException
+ extends Exception
+{
+ /**
+ * Constructs a <code>TransportException</code> with the
+ * given message
+ *
+ * @param message a message describing the exception
+ */
+ public TransportException (String message)
+ {
+ super (message);
+ }
+
+ /**
+ * Constructs a <code>TransportException</code> with the
+ * given <code>Throwable</code> 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 <keiths@redhat.com>
+ */
+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 <code>HashMap</code> 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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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 <aluchko@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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 <kgallowa@redhat.com>
+ */
+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
+ * <code>Executors.defaultThreadFactory()</code> plus calling
+ * <code>thread.setDaemon(true)</code> on the newly created thread.
+ *
+ * @author Mario Torre <neugens@limasoftware.net>
+ */
+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
+ * <code>listIndex</code>. 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 <code>true</code> if there are more visible components in the
+ * array, <code>false</code> otherwise.
+ *
+ * @return <code>true</code> if there are more visible components in the
+ * array, <code>false</code> 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 <code>Component</code> in the List.
+ *
+ * @return the next visible <code>Component</code> 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 <code>true</code> if there are more visible components in the
+ * array in the reverse direction, <code>false</code> otherwise.
+ *
+ * @return <code>true</code> if there are more visible components in the
+ * array in the reverse direction, <code>false</code> 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 <code>Component</code> in the List.
+ *
+ * @return the previous visible <code>Component</code> 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
+ * <code>Component[]</code>.
+ *
+ * @param c the <code>Component[]</code> 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 <code>c</code>
+ */
+ 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
+ * <code>null</code>
+ *
+ * @return The calculated area inside the base rectangle and its insets,
+ * either stored in ret or a new Rectangle if ret is <code>null</code>
+ *
+ * @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 <code>comp</code> 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 <code>comp</code> with the given
+ * name, or <code>null</code> 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 <code>comp</code> 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 <code>comp</code> which is an instance
+ * of the given class, or <code>null</code> 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 <code>getAncestorOfClass(Window, comp)</code>.
+ *
+ * @param comp The component to search for an ancestor window
+ *
+ * @return An ancestral window, or <code>null</code> if none exists
+ */
+ public static Window windowForComponent(Component comp)
+ {
+ return (Window) getAncestorOfClass(Window.class, comp);
+ }
+
+ /**
+ * Returns the "root" of the component tree containint <code>comp</code>
+ * The root is defined as either the <em>least</em> ancestor of
+ * <code>comp</code> which is a {@link Window}, or the <em>greatest</em>
+ * ancestor of <code>comp</code> 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 <code>null</code>
+ */
+ 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 <code>(x,y)</code>. Returns parent when either
+ * parent is not a container, or has no children which contain
+ * <code>(x,y)</code>. Returns <code>null</code> when either
+ * <code>(x,y)</code> is outside the bounds of parent, or parent is
+ * <code>null</code>.
+ *
+ * @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 <code>(x,y)</code>, or
+ * <code>null</code>
+ *
+ * @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 <code>(x,y)</code> from the coordinate space of one
+ * component to another. This is equivalent to converting the point from
+ * <code>source</code> space to screen space, then back from screen space
+ * to <code>destination</code> space. If exactly one of the two
+ * Components is <code>null</code>, it is taken to refer to the root
+ * ancestor of the other component. If both are <code>null</code>, 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 <code>(x,y)</code> 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
+ * <code>source</code> space to screen space, then back from screen space
+ * to <code>destination</code> space. If exactly one of the two
+ * Components is <code>null</code>, it is taken to refer to the root
+ * ancestor of the other component. If both are <code>null</code>, 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 <code>source</code> is
+ * <code>null</code>, it is taken to refer to <code>destination</code>'s
+ * root component. If <code>destination</code> is <code>null</code>, the
+ * new event will remain expressed in <code>source</code>'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<<bitWidth)-1) << leastSignificantBit;
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/BitwiseXORComposite.java b/libjava/classpath/gnu/java/awt/BitwiseXORComposite.java
new file mode 100644
index 000000000..e19b27fa9
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/BitwiseXORComposite.java
@@ -0,0 +1,295 @@
+/* BitwiseXORComposite.java -- Composite for emulating old-style XOR.
+ 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;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.CompositeContext;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.image.ColorModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+
+
+/**
+ * A composite for emulating traditional bitwise XOR of pixel values.
+ * Please note that this composite does <i>not</i> implement the Porter-Duff
+ * XOR operator, but an exclusive or of overlapping subpixel regions.
+ *
+ * <p><img src="doc-files/BitwiseXORComposite-1.png" width="545"
+ * height="138" alt="A screen shot of BitwiseXORComposite in action"
+ * />
+ *
+ * <p>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.
+ *
+ * <p>The purpose of this composite is to support the {@link
+ * Graphics#setXORMode(Color)} method in composite-aware graphics
+ * implementations. Applications typically would use
+ * <code>setXORMode</code> for drawing &#x201c;highlights&#x201d; such
+ * as text selections or cursors by inverting colors temporarily and
+ * then inverting them back.
+ *
+ * <p>A concrete <code>Graphics</code> implementation may contain
+ * the following code:
+ *
+ * <p><pre> public void setXORMode(Color xorColor)
+ * {
+ * setComposite(new gnu.java.awt.BitwiseXORComposite(xorColor));
+ * }
+ *
+ * public void setPaintMode()
+ * {
+ * setComposite(java.awt.AlphaComposite.SrcOver);
+ * }</pre>
+ *
+ * @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 <code>xorColor</code>.
+ *
+ * <p>Applying this CompositeContext on a 1024x1024 BufferedImage of
+ * <code>TYPE_INT_RGB</code> 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
+ * <code>int</code> pixel values with the pixel value of a specified
+ * <code>xorColor</code>. This CompositeContext working only for
+ * rasters whose transfer format is {@link DataBuffer#TYPE_INT}.
+ *
+ * <p>Applying this CompositeContext on a 1024x1024 BufferedImage of
+ * <code>TYPE_INT_RGB</code> 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 <fkung@redhat.com>
+ */
+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.
+ *
+ * <p>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.
+ *
+ * <p>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.
+ *
+ * <p><b>Thread Safety:</b> 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.
+ *
+ * <p>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.
+ *
+ * <p>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 <code>format</code> is
+ * not supported.
+ *
+ * @throws FontFormatException if <code>stream</code> 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 <code>stream</code>.
+ */
+ 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; yd<h; yd++)
+ {
+ System.arraycopy(srcArray, srcOffset,
+ destArray, destOffset,
+ rowSize);
+ srcOffset += srcScanlineStride;
+ destOffset += destScanlineStride;
+ }
+
+
+ return dest;
+ }
+
+ public Rectangle2D getBounds2D(Raster src)
+ {
+ return src.getBounds();
+ }
+
+ public WritableRaster createCompatibleDestRaster(Raster src) {
+
+ /* FIXME: Maybe we should explicitly create a raster with a
+ tightly pixel packed sample model, rather than assuming
+ that the createCompatibleWritableRaster() method in Raster
+ will create one. */
+
+ return src.createCompatibleWritableRaster();
+ }
+
+ public Point2D getPoint2D(Point2D srcPoint, Point2D destPoint)
+ {
+ if (destPoint == null)
+ return (Point2D) srcPoint.clone();
+
+ destPoint.setLocation(srcPoint);
+ return destPoint;
+ }
+
+ public RenderingHints getRenderingHints()
+ {
+ throw new UnsupportedOperationException("not implemented");
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/ComponentReshapeEvent.java b/libjava/classpath/gnu/java/awt/ComponentReshapeEvent.java
new file mode 100644
index 000000000..8f15c8519
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/ComponentReshapeEvent.java
@@ -0,0 +1,85 @@
+/* WindowResizeEvent.java -- Used to synchronize the AWT and peer sizes
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you 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.AWTEvent;
+import java.awt.Component;
+
+/**
+ * This is used to update the AWT's knowledge about a Window's size when
+ * the user changes the window bounds.
+ *
+ * This event is _not_ posted to the eventqueue, but rather dispatched directly
+ * via Window.dispatchEvent(). It is the cleanest way we could find to update
+ * the AWT's knowledge of the window size. Small testprograms showed the
+ * following:
+ * - Component.reshape() and its derivatives are _not_ called. This makes sense
+ * as it could end up in loops,because this calls back into the peers.
+ * - Intercepting event dispatching for any events in
+ * EventQueue.dispatchEvent() showed that the size is still updated. So it
+ * is not done via an event dispatched over the eventqueue.
+ *
+ * Possible other candidates for implementation would have been:
+ * - Call a (private) callback method in Window/Component from the native
+ * side.
+ * - Call a (private) callback method in Window/Component via reflection.
+ *
+ * Both is uglier than sending this event directly. Note however that this
+ * is impossible to test, as Component.dispatchEvent() is final and can't be
+ * intercepted from outside code. But this impossibility to test the issue from
+ * outside code also means that this shouldn't raise any compatibility issues.
+ */
+public class ComponentReshapeEvent
+ extends AWTEvent
+{
+
+ public int x;
+ public int y;
+ public int width;
+ public int height;
+
+ public ComponentReshapeEvent(Component c, int x, int y, int width, int height)
+ {
+ super(c, 1999);
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/EmbeddedWindow.java b/libjava/classpath/gnu/java/awt/EmbeddedWindow.java
new file mode 100644
index 000000000..6734a7b1b
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/EmbeddedWindow.java
@@ -0,0 +1,138 @@
+/* EmbeddedWindow.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.awt;
+
+import gnu.java.awt.peer.EmbeddedWindowPeer;
+import gnu.java.security.action.SetAccessibleAction;
+
+import java.awt.Component;
+import java.awt.Frame;
+import java.lang.reflect.Field;
+import java.security.AccessController;
+
+/**
+ * Represents an AWT window that can be embedded into another
+ * application.
+ *
+ * @author Michael Koch (konqueror@gmx.de)
+ */
+public class EmbeddedWindow extends Frame
+{
+ private long handle;
+
+ /**
+ * Creates a window to be embedded into another application. The
+ * window will only be embedded after its setHandle method has been
+ * called.
+ */
+ public EmbeddedWindow ()
+ {
+ super();
+ this.handle = 0;
+ }
+
+ /**
+ * Creates a window to be embedded into another application.
+ *
+ * @param handle the native handle to the screen area where the AWT
+ * window should be embedded
+ */
+ public EmbeddedWindow (long handle)
+ {
+ super();
+ this.handle = handle;
+ }
+
+ /**
+ * Creates the native peer for this embedded window.
+ */
+ public void addNotify()
+ {
+ // Assume we're using ClasspathToolkit
+ ClasspathToolkit tk = (ClasspathToolkit) getToolkit();
+
+ // Circumvent the package-privateness of the AWT internal
+ // java.awt.Component.peer member variable.
+ try
+ {
+ Field peerField = Component.class.getDeclaredField("peer");
+ AccessController.doPrivileged(new SetAccessibleAction(peerField));
+ peerField.set(this, tk.createEmbeddedWindow (this));
+ }
+ catch (IllegalAccessException e)
+ {
+ throw new AssertionError (e);
+ }
+ catch (NoSuchFieldException e)
+ {
+ throw new AssertionError (e);
+ }
+
+ super.addNotify();
+ }
+
+ /**
+ * If the native peer for this embedded window has been created,
+ * then setHandle will embed the window. If not, setHandle tells
+ * us where to embed ourselves when our peer is created.
+ *
+ * @param handle the native handle to the screen area where the AWT
+ * window should be embedded
+ */
+ public void setHandle(long handle)
+ {
+ if (this.handle != 0)
+ throw new RuntimeException ("EmbeddedWindow is already embedded");
+
+ this.handle = handle;
+ if (getPeer() != null)
+ ((EmbeddedWindowPeer) getPeer()).embed (this.handle);
+ }
+
+ /**
+ * Gets the native handle of the screen area where the window will
+ * be embedded.
+ *
+ * @return The native handle that was passed to the constructor.
+ */
+ public long getHandle()
+ {
+ return handle;
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/EventModifier.java b/libjava/classpath/gnu/java/awt/EventModifier.java
new file mode 100644
index 000000000..565fcbc32
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/EventModifier.java
@@ -0,0 +1,107 @@
+/* EventModifier.java -- tool for converting modifier bits to 1.4 syle
+ 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.awt;
+
+import java.awt.event.InputEvent;
+
+public class EventModifier
+{
+ /** The mask for old events. */
+ public static final int OLD_MASK = 0x3f;
+
+ /** The mask for new events. */
+ public static final int NEW_MASK = 0x3fc0;
+
+ /**
+ * Non-instantiable.
+ */
+ private EventModifier()
+ {
+ throw new InternalError();
+ }
+
+ /**
+ * Converts the old style modifiers (0x3f) to the new style (0xffffffc0).
+ *
+ * @param mod the modifiers to convert
+ * @return the adjusted modifiers
+ */
+ public static int extend(int mod)
+ {
+ // Favor what we hope will be the common case.
+ if ((mod & OLD_MASK) == 0)
+ return mod;
+ if ((mod & InputEvent.SHIFT_MASK) != 0)
+ mod |= InputEvent.SHIFT_DOWN_MASK;
+ if ((mod & InputEvent.CTRL_MASK) != 0)
+ mod |= InputEvent.CTRL_DOWN_MASK;
+ if ((mod & InputEvent.META_MASK) != 0)
+ mod |= InputEvent.META_DOWN_MASK;
+ if ((mod & InputEvent.ALT_MASK) != 0)
+ mod |= InputEvent.ALT_DOWN_MASK;
+ if ((mod & InputEvent.BUTTON1_MASK) != 0)
+ mod |= InputEvent.BUTTON1_DOWN_MASK;
+ if ((mod & InputEvent.ALT_GRAPH_MASK) != 0)
+ mod |= InputEvent.ALT_GRAPH_DOWN_MASK;
+ return mod & ~OLD_MASK;
+ }
+
+ /**
+ * Converts the new style modifiers (0xffffffc0) to the old style (0x3f).
+ *
+ * @param mod the modifiers to convert
+ * @return the adjusted modifiers
+ */
+ public static int revert(int mod)
+ {
+ if ((mod & InputEvent.SHIFT_DOWN_MASK) != 0)
+ mod |= InputEvent.SHIFT_MASK;
+ if ((mod & InputEvent.CTRL_DOWN_MASK) != 0)
+ mod |= InputEvent.CTRL_MASK;
+ if ((mod & InputEvent.META_DOWN_MASK) != 0)
+ mod |= InputEvent.META_MASK;
+ if ((mod & InputEvent.ALT_DOWN_MASK) != 0)
+ mod |= InputEvent.ALT_MASK;
+ if ((mod & InputEvent.ALT_GRAPH_DOWN_MASK) != 0)
+ mod |= InputEvent.ALT_GRAPH_MASK;
+ if ((mod & InputEvent.BUTTON1_DOWN_MASK) != 0)
+ mod |= InputEvent.BUTTON1_MASK;
+ return mod & OLD_MASK;
+ }
+} // class EventModifier
diff --git a/libjava/classpath/gnu/java/awt/GradientPaintContext.java b/libjava/classpath/gnu/java/awt/GradientPaintContext.java
new file mode 100644
index 000000000..f33926c12
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/GradientPaintContext.java
@@ -0,0 +1,164 @@
+/* GradientPaintContext.java --
+ Copyright (C) 2005, Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you 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.geom.Point2D;
+import java.awt.image.ColorModel;
+import java.awt.image.Raster;
+import java.awt.image.WritableRaster;
+import java.awt.PaintContext;
+import java.awt.Color;
+
+/**
+ * A {@link PaintContext} used by the {@link GradientPaint} class.
+ */
+public class GradientPaintContext implements PaintContext
+{
+
+ // This implementation follows the technique described in
+ // "Java(tm) 2D Graphics" by Jonathan Knudsen (O'Reilly 1999).
+
+ /** The x-coordinate of the anchor point for color 1. */
+ private final float x1;
+
+ /** The y-coordinate of the anchor point for color 1. */
+ private final float y1;
+
+ /** Color 1. */
+ private final Color c1;
+
+ /** The x-coordinate of the anchor point for color 2. */
+ private final float x2;
+
+ /** The y-coordinate of the anchor point for color 2. */
+ private final float y2;
+
+ /** Color 2. */
+ private final Color c2;
+
+ /** A flag indicating whether the gradient is cyclic or acyclic. */
+ private final boolean cyclic;
+
+ /** The length of the gradient line - computed from the two anchor points. */
+ private final double length;
+
+ /**
+ * Creates a new instance.
+ *
+ * @param x1 the x-coordinate for the anchor point for color 1.
+ * @param y1 the y-coordinate for the anchor point for color 1.
+ * @param c1 color 1.
+ * @param x2 the x-coordinate for the anchor point for color 2.
+ * @param y2 the y-coordinate for the anchor point for color 2.
+ * @param c2 color 2.
+ * @param cyclic a flag that determines whether the gradient is cyclic
+ * or acyclic.
+ */
+ public GradientPaintContext(float x1, float y1, Color c1,
+ float x2, float y2, Color c2, boolean cyclic)
+ {
+ this.x1 = x1;
+ this.y1 = y1;
+ this.c1 = c1;
+ this.x2 = x2;
+ this.y2 = y2;
+ this.c2 = c2;
+ this.cyclic = cyclic;
+ length = Point2D.distance(x1, y1, x2, y2);
+ }
+
+ /**
+ * Return the color model of this context. It may be different from the
+ * hint specified during createContext, as not all contexts can generate
+ * color patterns in an arbitrary model.
+ *
+ * @return the context color model
+ */
+ public ColorModel getColorModel()
+ {
+ return ColorModel.getRGBdefault();
+ }
+
+ /**
+ * Return a raster containing the colors for the graphics operation.
+ *
+ * @param x the x-coordinate, in device space
+ * @param y the y-coordinate, in device space
+ * @param w the width, in device space
+ * @param h the height, in device space
+ * @return a raster for the given area and color
+ */
+ public Raster getRaster(int x, int y, int w, int h) {
+ ColorModel cm = getColorModel();
+ WritableRaster raster = cm.createCompatibleWritableRaster(w, h);
+ int[] data = new int[w * h * 4];
+ double pd2 = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2);
+ for (int r = 0; r < h; r++) {
+ for (int c = 0; c < w; c++) {
+ double u = 0.0;
+ if (pd2 != 0)
+ u = (((x + c) - x1) * (x2 - x1) + ((y + r) - y1) * (y2 - y1))
+ / Math.sqrt(pd2);
+ double ratio = u / length;
+ if (cyclic)
+ ratio = Math.abs(ratio - Math.floor((ratio + 1.0) / 2.0) * 2.0);
+ else
+ ratio = Math.max(0.0, Math.min(1.0, ratio));
+ int base = (r * w + c) * 4;
+ data[base] = (int) (c1.getRed() + ratio * (c2.getRed() - c1.getRed()));
+ data[base + 1]
+ = (int) (c1.getGreen() + ratio * (c2.getGreen() - c1.getGreen()));
+ data[base + 2]
+ = (int) (c1.getBlue() + ratio * (c2.getBlue() - c1.getBlue()));
+ data[base + 3]
+ = (int) (c1.getAlpha() + ratio * (c2.getAlpha() - c1.getAlpha()));
+ }
+ }
+ raster.setPixels(0, 0, w, h, data);
+ return raster;
+ }
+
+ /**
+ * Release the resources allocated for the paint (none in this
+ * implementation).
+ */
+ public void dispose() {
+ // nothing to do
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/awt/LowPriorityEvent.java b/libjava/classpath/gnu/java/awt/LowPriorityEvent.java
new file mode 100644
index 000000000..c1558f6ff
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/LowPriorityEvent.java
@@ -0,0 +1,48 @@
+/* LowPriorityEvent.java -- Marks events with low priority
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you 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;
+
+/**
+ * A marker interface that marks events with low priority. LowPriority events
+ * are dispatched _after_ other (normal priority) events by the EventQueue.
+ */
+public interface LowPriorityEvent
+{
+ // Empty marker interface.
+}
diff --git a/libjava/classpath/gnu/java/awt/color/CieXyzConverter.java b/libjava/classpath/gnu/java/awt/color/CieXyzConverter.java
new file mode 100644
index 000000000..e1b548e98
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/color/CieXyzConverter.java
@@ -0,0 +1,73 @@
+/* CieXyzConverter.java -- CieXyz 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;
+
+
+/**
+ * CieXyzConverter - converts to/from a D50-relative CIE XYZ color space.
+ *
+ * The sRGB<->CIE 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 --&gt; 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.awt.color package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.awt.color</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/doc-files/BitwiseXORComposite-1.png
Binary files 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.
+ *
+ * <p><b>Thread Safety:</b> All classes that implement the
+ * <code>FontDelegate</code> 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 <i>&#x201c;Univers Light&#x201d;</i>.
+ *
+ * @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 <i>&#x201c;Univers&#x201d;</i>.
+ *
+ * @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
+ * <i>&#x201c;Light&#x201d;</i>.
+ *
+ * @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
+ * <i>&#x201c;Helvetica-Bold&#x201d;</i>.
+ *
+ * @return the PostScript name, or <code>null</code> 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.
+ *
+ * <p>The mapping takes only the font&#x2019;s <code>cmap</code>
+ * 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
+ * <code>FontRenderContext</code> correctly reflects the relevant
+ * parameters. Hence, <code>frc</code> should be obtained from the
+ * same <code>Graphics2D</code> that will be used for drawing, and
+ * any rendering hints should be set to the desired values before
+ * obtaining <code>frc</code>.
+ *
+ * @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 <code>true</code> for anti-aliased rendering,
+ * <code>false</code> for normal rendering. For hinted fonts,
+ * this parameter may indeed affect the result.
+ *
+ * @param fractionalMetrics <code>true</code> for fractional metrics,
+ * <code>false</code> for rounding the result to a pixel boundary.
+ *
+ * @param horizontal <code>true</code> for horizontal line layout,
+ * <code>false</code> for vertical line layout.
+ *
+ * @param advance a point whose <code>x</code> and <code>y</code>
+ * 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 <code>true</code> for anti-aliased rendering,
+ * <code>false</code> for normal rendering. For hinted fonts, this
+ * parameter may indeed affect the result.
+ *
+ * @param fractionalMetrics <code>true</code> for fractional
+ * metrics, <code>false</code> for rounding the result to a pixel
+ * boundary.
+ *
+ * @return the scaled and grid-fitted outline of the specified
+ * glyph, or <code>null</code> 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.
+ *
+ * <p><b>Names are not unique:</b> 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.</p>
+ *
+ * <p>This situation would occur for an OpenType or TrueType font
+ * that has a <code>post</code> table of format 3 and provides a
+ * mapping from glyph IDs to Unicode sequences through a
+ * <code>Zapf</code> 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 <code>true</code> for anti-aliased rendering,
+ * <code>false</code> for normal rendering. For hinted fonts,
+ * this parameter may indeed affect the result.
+ *
+ * @param fractionalMetrics <code>true</code> for fractional metrics,
+ * <code>false</code> for rounding the result to a pixel boundary.
+ *
+ * @param horizontal <code>true</code> for horizontal line layout,
+ * <code>false</code> 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 <code>true</code> for anti-aliased rendering,
+ * <code>false</code> for normal rendering. For hinted fonts,
+ * this parameter may indeed affect the result.
+ *
+ * @param fractionalMetrics <code>true</code> for fractional metrics,
+ * <code>false</code> for rounding the result to a pixel boundary.
+ *
+ * @param horizontal <code>true</code> for horizontal line layout,
+ * <code>false</code> 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:
+ *
+ * <p><ul>
+ * <li>OpenType (*.otf);</li>
+ * <li>TrueType (*.ttf);</li>
+ * <li>TrueType Collections (*.ttc);</li>
+ * <li>Apple MacOS X data-fork font (*.dfont).</li></ul>
+ *
+ * <p>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.
+ *
+ * <p>The implementation reads data from the buffer only when
+ * needed. Therefore, it greatly increases efficiency if
+ * <code>buf</code> 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
+ * <code>i</code>-th glyph is at <code>pos[i * 2]</code>, its
+ * vertical position at <code>pos[i * 2 + 1]</code>. The total
+ * advance width of the entire vector is stored at
+ * <code>pos[numGlyphs]</code>, the total advance height at
+ * <code>pos[numGlyphs + 1]</code>.
+ */
+ 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 <code>glyphIndex</code>
+ * is not in the range <code[0 .. getNumGlyphs() - 1]</code>.
+ */
+ 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 <code>null</code> to cause allocation of a new array.
+ *
+ * @return a slice of this GlyphVector. If <code>outCodes</code>
+ * is <code>null</code>, the slice will be stored into a freshly
+ * allocated array; otherwise, the result will be stored into
+ * <code>outCodes</code>.
+ */
+ 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 <code>glyphIndex</code> is
+ * not in the range <code[0 .. getNumGlyphs()]</code>.
+ */
+ 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 <code>getNumGlyphs()</code>, the
+ * position <i>after</i> the last glyph will be returned,
+ * which is the total advance width and height of the vector.
+ *
+ * @throws IndexOutOfBoundsException if <code>glyphIndex</code> is
+ * not in the range <code[0 .. getNumGlyphs()]</code>.
+ */
+ 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.
+ *
+ * <p>Note that the position of an individual glyph may also
+ * affected by its affine transformation.
+ *
+ * @param glyphIndex the index of the moved glyph. If
+ * <code>glyphIndex</code> 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 <code>glyphIndex</code> is
+ * not in the range <code[0 .. getNumGlyphs()]</code>.
+ */
+ 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 <code>null</code>
+ * for the identity transformation.
+ *
+ * @throws IndexOutOfBoundsException if <code>glyphIndex</code> is
+ * not in the range <code[0 .. getNumGlyphs() - 1]</code>.
+ */
+ 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
+ * <code>null</code> 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 <code>numGlyphs</code>),
+ * or <code>null</code> for freshly allocating an array.
+ *
+ * @return an array with the glyph positions. The horizontal
+ * position of the <code>i</code>-th glyph is at index <code>2 *
+ * i</code>, the vertical position at index <code>2 * i + 1</code>.
+ *
+ * @throws IllegalArgumentException if <code>numGlyphs</code>
+ * is less than zero.
+ *
+ * @throws IndexOutOfBoundsException if either
+ * <code>firstGlyphIndex</code> or <code>(firstGlyphIndex +
+ * numGlyphs)</code> is not in the range <code>[0 .. getNumGlyphs() -
+ * 1]</code>.
+ */
+ 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 <code>glyphIndex</code> is
+ * not in the range <code[0 .. getNumGlyphs() - 1]</code>.
+ */
+ 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 <code>glyphIndex</code> is
+ * not in the range <code[0 .. getNumGlyphs() - 1]</code>.
+ */
+ 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 <code>true</code> if the two vectors are equal,
+ * <code>false</code> 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<String> availableFontNames;
+
+ /**
+ * Font spec to file mapping.
+ */
+ private static Map<String,Map<String,String>> 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<String> fontNames = getFontNames();
+ if (fontNames.contains(name))
+ {
+ retVal = name;
+ }
+ else
+ {
+ retVal = "SansSerif";
+ }
+ return retVal;
+ }
+
+ public static String[] getAvailableFontFamilyNames(Locale l)
+ {
+ Set<String> fontNames = getFontNames();
+ int numNames = fontNames.size();
+ String[] ret = fontNames.toArray(new String[numNames]);
+ return ret;
+ }
+
+ private static synchronized Set<String> getFontNames()
+ {
+ if (availableFontNames == null)
+ {
+ HashSet<String> familyNames = new HashSet<String>();
+ 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 <code>null</code> 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<String,Map<String,String>>();
+
+ // 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<String,String> specToFileMap = fontToFileMap.get(name);
+ if (specToFileMap == null)
+ {
+ specToFileMap = new HashMap<String,String>();
+ 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<String,String> 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 <code>hints</code> 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<Segment> touched = new HashSet<Segment>();
+ 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.
+ *
+ * <p>This class manages the <code>cmap</code> table of
+ * OpenType and TrueType fonts.
+ *
+ * @see <a href="http://partners.adobe.com/asn/tech/type/opentype/cmap.jsp">
+ * the <code>cmap</code> part of Adobe&#x2019; OpenType Specification</a>
+ *
+ * @see <a href="http://developer.apple.com/fonts/TTRefMan/RM06/Chap6cmap.html">
+ * the <code>cmap</code> section of Apple&#x2019;s TrueType Reference
+ * Manual</a>
+ *
+ * @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 <code>cmap</code> 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 <code>cmap</code>
+ * table. The current implementation works as follows:
+ *
+ * <p><ol><li>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.</li>
+ *
+ * <li>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.</li>.</ol>
+ *
+ * @param buf a buffer whose position is right at the start
+ * of the entire <code>cmap</code> table, and whose limit
+ * is at its end.
+ *
+ * @return a concrete subclass of <code>CharGlyphMap</code>
+ * that performs the mapping.
+ *
+ * @see <a href=
+ * "http://partners.adobe.com/asn/tech/type/opentype/cmap.jsp"
+ * >the <code>cmap</code> part of Adobe&#x2019; OpenType Specification</a>
+ *
+ * @see <a href=
+ * "http://developer.apple.com/fonts/TTRefMan/RM06/Chap6cmap.html"
+ * >the <code>cmap</code> section of Apple&#x2019;s TrueType Reference
+ * Manual</a>
+ */
+ 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.
+ *
+ * <p>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 <code>i</code>-th element indicates the
+ * Unicode code point of glyph <code>i</code> in the font.
+ */
+ private char[] glyphToUCS2 = new char[256];
+
+
+ /**
+ * A String whose <code>charAt(i)</code> is the Unicode character
+ * that corresponds to the codepoint <code>i + 127</code> in the
+ * MacOS Arabic encoding.
+ *
+ * @see <a href=
+ * "http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/ARABIC.TXT"
+ * >the Unicode mapping table for the MacOS Arabic encoding</a>
+ */
+ 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 <code>charAt(i)</code> is the Unicode character
+ * that corresponds to the codepoint <code>i + 127</code> in the
+ * MacOS East European Roman encoding.
+ *
+ * @see <a href=
+ * "http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CENTEURO.TXT"
+ * >the Unicode mapping table for the MacOS Central European
+ * encoding</a>
+ */
+ 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 <code>charAt(i)</code> is the Unicode character
+ * that corresponds to the codepoint <code>i + 127</code> in the
+ * MacOS Roman encoding for the Croatian language.
+ *
+ * @see <a href=
+ * "http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CROATIAN.TXT"
+ * >the Unicode mapping table for the MacOS Croatian encoding</a>
+ */
+ 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 <code>charAt(i)</code> is the Unicode character
+ * that corresponds to the codepoint <code>i + 127</code> in the
+ * MacOS Cyrillic encoding.
+ *
+ * @see <a href=
+ * "http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/CYRILLIC.TXT"
+ * >the Unicode mapping table for the MacOS Cyrillic encoding</a>
+ */
+ 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 <code>charAt(i)</code> is the Unicode character
+ * that corresponds to the codepoint <code>i + 127</code> in the
+ * MacOS Arabic encoding with the Farsi language.
+ *
+ * @see <a href=
+ * "http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/FARSI.TXT"
+ * >the Unicode mapping table for the MacOS Farsi encoding</a>
+ */
+ 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 <code>charAt(i)</code> is the Unicode character
+ * that corresponds to the codepoint <code>i + 127</code> in the
+ * MacOS Greek encoding.
+ *
+ * @see <a
+ * href="http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/GREEK.TXT"
+ * >the Unicode mapping table for the MacOS Greek encoding</a>
+ */
+ 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 <code>charAt(i)</code> is the Unicode character
+ * that corresponds to the codepoint <code>i + 127</code> in the
+ * MacOS Hebrew encoding.
+ *
+ * <p>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 <a href=
+ * "http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/HEBREW.TXT"
+ * >the Unicode mapping table for the MacOS Hebrew encoding</a>
+ */
+ 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 <code>charAt(i)</code> is the Unicode character
+ * that corresponds to the codepoint <code>i + 127</code> in the
+ * MacOS Roman encoding with the Icelandic language.
+ *
+ * @see <a href=
+ * "http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/ICELAND.TXT"
+ * >the Unicode mapping table for the MacOS Icelandic encoding</a>
+ */
+ 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 <code>charAt(i)</code> is the Unicode character
+ * that corresponds to the codepoint <code>i + 127</code> in the
+ * MacOS Roman encoding for most languages. Exceptions include
+ * Croatian, Icelandic, Romanian, and Turkish.
+ *
+ * @see <a
+ * href="http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/ROMAN.TXT"
+ * >the Unicode mapping table for the MacOS Roman encoding</a>
+ */
+ 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 <code>charAt(i)</code> is the Unicode character
+ * that corresponds to the codepoint <code>i + 127</code> in the
+ * MacOS Roman encoding with the Romanian language.
+ *
+ * @see <a href=
+ * "http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/ROMANIAN.TXT"
+ * >the Unicode mapping table for the MacOS Romanian encoding</a>
+ */
+ 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 <code>charAt(i)</code> is the Unicode character
+ * that corresponds to the codepoint <code>i + 127</code> in the
+ * MacOS Roman encoding with the Turkish language.
+ *
+ * @see <a href=
+ * "http://www.unicode.org/Public/MAPPINGS/VENDORS/APPLE/TURKISH.TXT"
+ * >the Unicode mapping table for the MacOS Turkish encoding</a>
+ */
+ 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 (<i>not</i>
+ * 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 <code>charAt(i)</code> is the Unicode
+ * character that corresponds to the codepoint <code>i +
+ * 127</code> 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 <i>plus one.</i> 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 <code>platform</code> is not <code>1</code>
+ * (indicating Macintosh), or if the combination of
+ * <code>script</code> and <code>language</code> is not
+ * recognized, <code>null</code> 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
+ * <code>cmap</code> table.
+ *
+ * <p>Currently, we support the following combinations:
+ *
+ * <ul><li>the Unicode platform in encodings 0, 1, 2, 3 and
+ * 4;</li>
+ *
+ * <li>the Microsoft platform in encodings 1 (Basic Multilingual
+ * Plane) and 10 (full Unicode).</li></ul>
+ *
+ * <p>Most recent Macintosh fonts provide a type 4
+ * <code>cmap</code> for Unicode. Microsoft recommends providing a
+ * type 4 <code>cmap</code> for encoding 1 of the Microsoft
+ * platform. The implementation of GNU Classpath supports both
+ * variants.
+ *
+ * <p>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 <code>null</code> 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 <code>cmap</code> table.
+ *
+ * <p>Currently, we support the following combinations:
+ *
+ * <ul><li>the Unicode platform in encodings 0, 1, 2, 3 and
+ * 4;</li>
+ *
+ * <li>the Microsoft platform in encodings 1 (Basic Multilingual
+ * Plane) and 10 (full Unicode).</li></ul>
+ */
+ 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 <code>cmap</code> 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 <code>cmap</code> 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.
+ *
+ * <p>If the font has a <code>Zapf</code> 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&#x2019;s conventions. This allows to extract the
+ * original text from the generated PDF or PostScript file, which is
+ * important for indexing, searching and extracting.
+ *
+ * <p>Otherwise, glyph names are taken from the <a href=
+ * "http://developer.apple.com/fonts/TTRefMan/RM06/Chap6post.html"
+ * ><code>post</code> table</a>. All known formats (1, 2, 2.5, 3 and
+ * 4) are supported.
+ *
+ * <p><b>Open Tasks:</b> 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.
+ *
+ * <p><b>Lack of Thread Safety:</b> The GlyphNamer class is
+ * intentionally <i>not</i> 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 <code>maxp</code> 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.
+ *
+ * <p>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.
+ *
+ * <p>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 <code>A</code>,
+ * <code>gcircumflex</code>, <code>z_uni0302</code>, or
+ * <code>u11C42</code>.</li>
+ */
+ 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 <a href=
+ * "http://developer.apple.com/fonts/TTRefMan/RM06/Chap6Zapf.html">
+ * Apple&#x2019;s documentation of the <code>Zapf</code> table</a>
+ */
+ 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 <code>post</code> 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 <a href=
+ * "http://partners.adobe.com/asn/tech/type/aglfn13.txt" >Adobe
+ * Glyph List for New Fonts</a>
+ */
+ 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 <a href=
+ * "http://partners.adobe.com/asn/tech/type/aglfn13.txt" >Adobe
+ * Glyph List for New Fonts</a>
+ */
+ 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).
+ *
+ * <p>Generated from the Adobe Glyph List for New Fonts, version 1.1
+ * of 17 April 2003.
+ *
+ * @see <a href=
+ * "http://partners.adobe.com/asn/tech/type/aglfn13.txt" >Adobe
+ * Glyph List for New Fonts</a>
+ */
+ 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 <code>0x010a</code> for <code>LATIN CAPITAL LETTER C WITH
+ * DOT ABOVE</code>.
+ *
+ * @return the glyph name, for example <code>Cdotaccent</code>. If
+ * the glyph is not in the <i>Adobe Glyph List for New Fonts</i>,
+ * <code>null</code> is returned.
+ *
+ * @see <a href=
+ * "http://partners.adobe.com/asn/tech/type/aglfn13.txt" >Adobe
+ * Glyph List for New Fonts (AGLFN), version 1.1 of April 17,
+ * 2003</a>
+ *
+ * @see <a href=
+ * "http://partners.adobe.com/asn/developer/type/unicodegn.html#6"
+ * >Adobe&#x2019;s guidelines related to Unicode</a>
+ */
+ 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&#x2019;s glyph naming recommendations
+ * in order to allow searching and indexing of the produced
+ * PostScript and PDF.
+ *
+ * <p>Some examples:
+ * <ul><li><code>U+0041</code> gives <code>A</code>;</li>
+ * <li><code>U+011D</code> gives <code>gcircumflex</code>;</li>
+ * <li><code>U+007A U+0302</code> gives <code>z_uni0302</code>;</li>
+ * <li><code>U+D807 U+DC42</code> (an UTF-16 escape sequence)
+ * gives <code>u11C42</code>;</li>
+ * </ul>.
+ *
+ * <p>The routine does <i>not</i> bring sequences in any canonical
+ * form. Therefore, the result for <code>U+0067 U+0302</code> (the
+ * decomposition of <code>U+011D</code>) will be
+ * <code>g_uni0302</code>, not <code>gcircumflex</code>.
+ *
+ * @see <a href=
+ * "http://partners.adobe.com/asn/tech/type/unicodegn.jsp" >Unicode
+ * and Glyph Names</a> and <a href=
+ * "http://partners.adobe.com/asn/tech/type/glyphnamelimits.jsp"
+ * >Glyph Names and Current Implementations</a>
+ */
+ 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.
+ *
+ * <p>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.
+ *
+ * <p>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.
+ *
+ * <p>Thread Safety: All access is synchronized on the ByteBuffer
+ * that is passed to the constructor.
+ *
+ * @see <a href=
+ * "http://developer.apple.com/documentation/mac/MoreToolbox/MoreToolbox-99.html"
+ * >Apple&#x2019; developer documentation about the Resource File
+ * Format</a>
+ *
+ * @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 <code>int</code> encoding a four-byte type tag,
+ * such as <code>0x464f4e54</code> for <code>'FONT'</code>.
+ */
+ 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 &#x201c;Univers&#x201d;.
+ */
+ public static final int NAME_FAMILY = 1;
+
+
+ /**
+ * Specified the name of the font inside its family, for
+ * example &#x201c;Light&#x201d;.
+ */
+ 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
+ * &#x201c;Univers Light&#x201d;
+ */
+ public static final int NAME_FULL = 4;
+
+
+ public static final int NAME_VERSION = 5;
+
+
+ /**
+ * Specifies the PostScript name of a font, for example
+ * &#x201c;Univers-Light&#x201d;.
+ */
+ 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.
+ *
+ * <p>ISO 639 has revised the code for some languages, namely
+ * <code>he</code> for Hebrew (formerly <code>iw</code>),
+ * <code>yi</code> (formerly <code>ji</code>), and <code>id</code>
+ * for Indonesian (formerly <code>in</code>). 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 <a href=
+ * "http://www.unicode.org/unicode/onlinedat/languages.html"
+ * >Language Codes: ISO 639, Microsoft and Macintosh</a>
+ */
+ 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.
+ *
+ * <p>ISO 639 has revised the code for some languages, namely
+ * <code>he</code> for Hebrew (formerly <code>iw</code>),
+ * <code>yi</code> (formerly <code>ji</code>), and <code>id</code>
+ * for Indonesian (formerly <code>in</code>). 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 <a href=
+ * "http://www.unicode.org/unicode/onlinedat/languages.html"
+ * >Language Codes: ISO 639, Microsoft and Macintosh</a>
+ */
+ 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.
+ *
+ * <p>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).</p>
+ *
+ * <p>The following cases are problematic:
+ *
+ * <ul> <li>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.</li>
+ *
+ * <li>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.</li>
+ *
+ * <li>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.</li> </ul>
+ *
+ * @return a MacOS language code, or -1 if there is no such code for
+ * <code>loc</code>&#x2019;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 <code>null</code> 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 <code>null</code> 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 <code>smGreek</code>.
+ *
+ * @return a String that can be used to retrieve a Java
+ * CharsetDecorder, for example <code>MacGreek</code>, or
+ * <code>null</code> if <code>macScript</code> 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 <code>windows-1252</code>, or
+ * <code>null</code> if <code>lcid</code> 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
+ * <code>platform</code> is 1, this is the MacOS language code.
+ *
+ * @param encoding the encoding tag of the OpenType name. If
+ * <code>platform</code> 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
+ * <code>platform</code> is 1, this is the MacOS language code.
+ *
+ * @param encoding the encoding tag of the OpenType name. If
+ * <code>platform</code> is 1, this is the MacOS script code.
+ *
+ * @return a charset name such as <code>&quot;MacRoman&quot;</code>,
+ * or <code>null</code> 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.
+ *
+ * <p>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 <a
+ * href="http://partners.adobe.com/asn/tech/type/opentype/">Adobe&#x2019;s
+ * OpenType specification</a>
+ *
+ * @see <a
+ * href="http://developer.apple.com/fonts/TTRefMan/">Apple&#x2019;s</code>
+ * TrueType specification</a>
+ *
+ * @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 <code>1 /
+ * unitsPerEm</code>.
+ */
+ 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 <code>MappedByteBuffer</code> 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 <code>tableStart[getTableIndex(TAG_NAME)]</code>.
+ *
+ * @param tag the table identifier, for instance
+ * <code>OpenType.TAG_NAME</code>.
+ *
+ * @return the index of that table into the offset table, or
+ * -1 if the font does not contain the table specified by
+ * <code>tag</code>.
+ */
+ 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 <i>&#x201c;Univers&#x201d;</i>.
+ *
+ * @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
+ * <i>&#x201c;Light&#x201d;</i>.
+ *
+ * @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
+ * <i>&#x201c;Univers Light&#x201d;</i>.
+ *
+ * @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
+ * <i>&#x201c;Univers-Light&#x201d;</i>.
+ *
+ * @return the PostScript name, or <code>null</code> 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&#x2019;s name table, or <code>null</code> if this
+ * table has not yet been accessed.
+ */
+ private ByteBuffer nameTable;
+
+
+ /**
+ * Extracts a String from the font&#x2019;s name table.
+ *
+ * @param name the numeric TrueType or OpenType name ID.
+ *
+ * @param locale the locale for which names shall be localized, or
+ * <code>null</code> 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
+ * <code>OpenType.GLYF</code>.
+ *
+ * @return a slice of the underlying buffer containing the table, or
+ * <code>null</code> 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&#x2019;s <code>cmap</code> 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.
+ *
+ * <p>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.
+ *
+ * <p>The mapping takes only the font&#x2019;s <code>cmap</code>
+ * 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
+ * <code>FontRenderContext</code> correctly reflects the relevant
+ * parameters. Hence, <code>frc</code> should be obtained from the
+ * same <code>Graphics2D</code> that will be used for drawing, and
+ * any rendering hints should be set to the desired values before
+ * obtaining <code>frc</code>.
+ *
+ * @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 <code>true</code> for anti-aliased rendering,
+ * <code>false</code> for normal rendering. For hinted fonts,
+ * this parameter may indeed affect the result.
+ *
+ * @param fractionalMetrics <code>true</code> for fractional metrics,
+ * <code>false</code> for rounding the result to a pixel boundary.
+ *
+ * @param horizontal <code>true</code> for horizontal line layout,
+ * <code>false</code> for vertical line layout.
+ *
+ * @param advance a point whose <code>x</code> and <code>y</code>
+ * fields will hold the advance in each direction. It is possible
+ * that both values are non-zero, for example if
+ * <code>transform</code> 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 <code>true</code> for anti-aliased rendering,
+ * <code>false</code> for normal rendering. For hinted fonts, this
+ * parameter may indeed affect the result.
+ *
+ * @param fractionalMetrics <code>true</code> for fractional
+ * metrics, <code>false</code> for rounding the result to a pixel
+ * boundary.
+ *
+ * @return the scaled and grid-fitted outline of the specified
+ * glyph, or <code>null</code> 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.
+ *
+ * <p><b>Names are not unique:</b> 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.</p>
+ *
+ * <p>This situation would occur for an OpenType or TrueType font
+ * that has a <code>post</code> table of format 3 and provides a
+ * mapping from glyph IDs to Unicode sequences through a
+ * <code>Zapf</code> 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 <code>true</code> for anti-aliased rendering,
+ * <code>false</code> for normal rendering. For hinted fonts,
+ * this parameter may indeed affect the result.
+ *
+ * @param fractionalMetrics <code>true</code> for fractional metrics,
+ * <code>false</code> for rounding the result to a pixel boundary.
+ *
+ * @param horizontal <code>true</code> for horizontal line layout,
+ * <code>false</code> 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 <code>true</code> for anti-aliased rendering,
+ * <code>false</code> for normal rendering. For hinted fonts,
+ * this parameter may indeed affect the result.
+ *
+ * @param fractionalMetrics <code>true</code> for fractional metrics,
+ * <code>false</code> for rounding the result to a pixel boundary.
+ *
+ * @param horizontal <code>true</code> for horizontal line layout,
+ * <code>false</code> 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 <code>int</code>.
+ *
+ * @return the tag in human-readable form, for example
+ * <code>name</code> or <code>glyf</code>.
+ */
+ 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
+ * <i>sfnt</i>-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:
+ *
+ * <p><ul>
+ * <li>OpenType (*.otf);</li>
+ * <li>TrueType (*.ttf);</li>
+ * <li>TrueType Collections (*.ttc);</li>
+ * <li>Apple MacOS X data-fork font (*.dfont).</li></ul>
+ *
+ * <p>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.
+ *
+ * <p>The implementation reads data from the buffer only when
+ * needed. Therefore, it greatly increases efficiency if
+ * <code>buf</code> 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.
+ *
+ * <p>To make text more legible, high-quality fonts contain
+ * instructions (sometimes also called &#x201c;hints&#x201d;) for
+ * moving the scaled control points towards the coordinate grid of the
+ * display device.
+ *
+ * <p><b>Lack of Thread Safety:</b> Font scalers are intentionally
+ * <i>not</i> 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 <code>false</code> for adjusting glyph
+ * positions to the raster grid of device space.
+ *
+ * @return the scaled and grid-fitted outline of the specified
+ * glyph, or <code>null</code> 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 <code>true</code> for anti-aliased rendering,
+ * <code>false</code> for normal rendering. For hinted fonts,
+ * this parameter may indeed affect the result.
+ *
+ * @param fractionalMetrics <code>true</code> for fractional metrics,
+ * <code>false</code> for rounding the result to a pixel boundary.
+ *
+ * @param horizontal <code>true</code> for horizontal line layout,
+ * <code>false</code> for vertical line layout.
+ *
+ * @param advance a point whose <code>x</code> and <code>y</code>
+ * 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 <code>true</code> for anti-aliased rendering,
+ * <code>false</code> for normal rendering. For hinted fonts,
+ * this parameter may indeed affect the result.
+ *
+ * @param fractionalMetrics <code>true</code> for fractional metrics,
+ * <code>false</code> for rounding the result to a pixel boundary.
+ *
+ * @param horizontal <code>true</code> for horizontal line layout,
+ * <code>false</code> 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 <code>true</code> for anti-aliased rendering,
+ * <code>false</code> for normal rendering. For hinted fonts,
+ * this parameter may indeed affect the result.
+ *
+ * @param fractionalMetrics <code>true</code> for fractional metrics,
+ * <code>false</code> for rounding the result to a pixel boundary.
+ *
+ * @param horizontal <code>true</code> for horizontal line layout,
+ * <code>false</code> 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.
+ *
+ * <p>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.
+ *
+ * <p><b>Lack of Thread Safety:</b> Glyph loaders are intentionally
+ * <i>not</i> 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
+ * <code>pointFlags</code> 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 <code>glyf</code>
+ * table.
+ *
+ * @see <a href=
+ * "http://partners.adobe.com/asn/tech/type/opentype/loca.html"
+ * >Adobe&#x2019;s specification of the OpenType &#x2018;loca&#x2019;
+ * table</a>
+ *
+ * @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 <code>loca</code> table.
+ *
+ * @param format the format of the <code>loca</code> 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
+ * <code>indexToLoc</code> field of the <a href=
+ * "http://partners.adobe.com/asn/tech/type/opentype/head.html"
+ * >font header</a>.
+ *
+ * @param loca the <code>loca</code> table of the font, which
+ * contains the position of each glyph in the <code>glyf</code>
+ * table.
+ *
+ * @param glyf the <code>glyf</code> table of the font, which
+ * contains the outline data of each glyph.
+ *
+ * @throws FontFormatException if <code>format</code> 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.
+ *
+ * <p>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 <code>null</code>.
+ */
+ public abstract ByteBuffer getGlyphData(int glyph);
+
+
+ /**
+ * A GlyphLocator that locates glyphs using two-byte offsets,
+ * interpreting <code>loca</code> 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 <code>loca</code> 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.
+ *
+ * <p><b>Lack of Thread Safety:</b> Glyph measurers are intentionally
+ * <i>not</i> 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&#x2019;s <code>hmtx</code> table as shorts.
+ */
+ private final ShortBuffer horizontalGlyphMetrics;
+
+
+ /**
+ * A view buffer that allows accessing the contents of the
+ * font&#x2019;s <code>vmtx</code> 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 <code>hhea</code> table, which contains
+ * information about horizontal metrics that is common to all
+ * glyphs.
+ *
+ * @param hmtx the <code>hmtx</code> table, which contains
+ * glyph-specific information about horizontal metrics.
+ *
+ * @param vhea the <code>vhea</code> table, which contains
+ * information about vertical metrics that is common to all
+ * glyphs. If a font does not provide such a table, pass
+ * <code>null</code>.
+ *
+ * @param vmtx the <code>vmtx</code> table, which contains
+ * glyph-specific information about vertical metrics. If a font
+ * does not provide such a table, pass <code>null</code>.
+ */
+ 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 <code>true</code> for horizontal line layout,
+ * <code>false</code> 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 <code>true</code> for horizontal line layout,
+ * <code>false</code> 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 <code>true</code> for horizontal line layout,
+ * <code>false</code> 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 <code>true</code> for horizontal line layout,
+ * <code>false</code> 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 <code>true</code> for horizontal line layout,
+ * <code>false</code> 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.
+ *
+ * <p><b>Lack of Thread Safety:</b> Font scalers are intentionally
+ * <i>not</i> 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&#x2019;s <code>head</code> table.
+ *
+ * @param maxp the <code>maxp</code> table of the font, which
+ * contains various constants needed for setting up the virtual
+ * machine that interprets TrueType bytecodes.
+ *
+ * @param controlValueTable the <code>cvt</code> table of the font,
+ * which contains the initial values of the control value table.
+ *
+ * @param fpgm the <code>fpgm</code> 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 <code>loca</code> 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
+ * <code>indexToLoc</code> field of the <a href=
+ * "http://partners.adobe.com/asn/tech/type/opentype/head.html"
+ * >font header</a>.
+ *
+ * @param loca the <code>loca</code> table of the font, which
+ * contains for each glyph the offset of its outline data
+ * in <code>glyf</code>.
+ *
+ * @param glyf the <code>glyf</code> table of the font, which
+ * contains the outline data for all glyphs in the font.
+ *
+ * @param preProgram the <code>prep</code> 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 <code>null</code>.
+ *
+ * @throws FontFormatException if <code>format</code> 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 <code>false</code> 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 <code>true</code> for anti-aliased rendering,
+ * <code>false</code> for normal rendering. For hinted fonts,
+ * this parameter may indeed affect the result.
+ *
+ * @param fractionalMetrics <code>true</code> for fractional metrics,
+ * <code>false</code> for rounding the result to a pixel boundary.
+ *
+ * @param horizontal <code>true</code> for horizontal line layout,
+ * <code>false</code> for vertical line layout.
+ *
+ * @param advance a point whose <code>x</code> and <code>y</code>
+ * fields will hold the advance in each direction. It is possible
+ * that both values are non-zero, for example if
+ * <code>transform</code> 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 <code>true</code> for fractional
+ * metrics, <code>false</code> for rounding the result to a pixel
+ * boundary.
+ *
+ * @param horizontal <code>true</code> if the <code>funits</code>
+ * value is along the x axis, <code>false</code> 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 <code>true</code> for anti-aliased rendering,
+ * <code>false</code> for normal rendering. For hinted fonts,
+ * this parameter may indeed affect the result.
+ *
+ * @param fractionalMetrics <code>true</code> for fractional metrics,
+ * <code>false</code> for rounding the result to a pixel boundary.
+ *
+ * @param horizontal <code>true</code> for horizontal line layout,
+ * <code>false</code> 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 <code>true</code> for anti-aliased rendering,
+ * <code>false</code> for normal rendering. For hinted fonts,
+ * this parameter may indeed affect the result.
+ *
+ * @param fractionalMetrics <code>true</code> for fractional metrics,
+ * <code>false</code> for rounding the result to a pixel boundary.
+ *
+ * @param horizontal <code>true</code> for horizontal line layout,
+ * <code>false</code> 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.
+ *
+ * <p><b>Lack of Thread Safety:</b> The virtual machine is
+ * intentionally <i>not</i> 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.
+ *
+ * <p><b>Implementation Status:</b> 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.
+ *
+ * <p><b>Patents:</b> 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.
+ *
+ * <p>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.</p>
+ *
+ * <p>The relevant patents are listed subsequently.</p>
+ *
+ * <p><ol><li>United States Patent 5155805, <i>Method and Apparatus
+ * for Moving Control Points in Displaying Digital Typeface on Raster
+ * Output Devices,</i> invented by Sampo Kaasila, assigned to Apple
+ * Computer. Filing date: May 8, 1989. Date of patent: October 13,
+ * 1992.</li>
+ *
+ * <li>United States Patent 5159668, <i>Method and Apparatus for
+ * Manipulating Outlines in Improving Digital Typeface on Raster
+ * Output Devices,</i> invented by Sampo Kaasila, assigned to Apple
+ * Computer. Filing date: May 8, 1989. Date of patent: October 27,
+ * 1992.</li>
+ *
+ * <li>United States Patent 5325479, <i>Method and Apparatus for
+ * Moving Control Points in Displaying Digital Typeface on Raster
+ * Output Devices,</i> invented by Sampo Kaasila, assigned to Apple
+ * Computer. Filing date: May 28, 1989. Date of patent: June 28, 1994
+ * (with a statement that &#x201c;[t]he portion of the term of this
+ * patent subsequent to Oct. 13, 2009 has been
+ * disclaimed&#x201d;).</li></ol>
+ *
+ * @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
+ * <code>sp[0]</code> gets used before <code>sp[1]</code>.
+ */
+ 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 <code>null</code>.
+ */
+ 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&#x2019;s <code>fpgm</code> table, or
+ * <code>null</code> after the font program has been executed once.
+ */
+ private ByteBuffer fontProgram;
+
+
+ /**
+ * The <code>prep</code> 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 <code>null</code>.
+ */
+ 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 <code>GETINFO</code> 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&#x2019;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
+ * <code>roundPeriod</code>.
+ */
+ 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 <code>prep</code> 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 <code>null</code>.
+ */
+ 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&#x2019;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 <code>pointSize</code>. 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 <code>true</code> if the scan-line conversion
+ * algorithm will use gray levels to give a smoother appearance,
+ * <code>false</code> otherwise. Font programs can ask for this
+ * value with the <code>GETINFO</code> 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 <code>System.out</code>.
+ * 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 <code>inst</code> is right after the first
+ * occurence of <code>opcode</code>.
+ *
+ * @param opcode1 the opcode for which to look.
+ *
+ * @param opcode2 another opcode for which to look. Pass -1
+ * if only <code>opcode1</code> 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 <code>true</code> to handle
+ * nested <code>IF [ELSE] EIF</code> clauses, <code>false</code>
+ * 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 <code>illegalCode1</code> or
+ * <code>illegalCode2</code> 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 <code>NPUSHB</code> and <code>NPUSHW</code>, 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 <code>true</code> if another instruction shall be
+ * executed in the same call frame; <code>false</code> 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 <code>SROUND</code> instruction or
+ * <code>sqrt(2)/2</code> for the <code>S45ROUND</code> 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 <code>pairs</code>.
+ *
+ * @param numPairs the number of pairs.
+ *
+ * @param base 0 for <code>DELTAC1</code>, 16 for <code>DELTAC2</code>,
+ * or 32 for <code>DELTAC2</code>.
+ *
+ * @see <a href=
+ * "http://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html#DELTAC1"
+ * >Apple&#x2019;s documentation for <code>DELTAC1</code></a>, <a href=
+ * "http://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html#DELTAC2"
+ * ><code>DELTAC2</code></a>, and <a href=
+ * "http://developer.apple.com/fonts/TTRefMan/RM05/Chap5.html#DELTAC3"
+ * ><code>DELTAC3</code></a>
+ */
+ 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 <code>false</code> if the shearing factors for the
+ * <i>x</i> and <i>y</i> axes are zero; <code>true</code> if they
+ * are non-zero.
+ */
+ private boolean isRotated()
+ {
+ return (shearX != 0) || (shearY != 0);
+ }
+
+
+ /**
+ * Determines whether the current glyph is stretched.
+ *
+ * @return <code>false</code> if the scaling factors for the
+ * <i>x</i> and <i>y</i> axes are are equal; <code>true</code> 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.
+ *
+ * <p><b>Lack of thread safety:</b> Instances of this class are
+ * <i>not</i> safe to access from multiple concurrent threads.
+ *
+ * @see Zone
+ *
+ * @author Sascha Brawer (brawer@dandelis.ch)
+ */
+final class ZonePathIterator
+ implements PathIterator
+{
+ /**
+ * If <code>state</code> has this value, <code>currentSegment</code>
+ * will emit a <code>SEG_LINETO</code> or <code>SEG_QUADTO</code> 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 <code>state</code> has this value, <code>currentSegment</code>
+ * will emit a <code>SEG_CLOSE</code> in order to close the sub-path
+ * for the current contour.
+ */
+ private static final int EMIT_CLOSE = 1;
+
+
+ /**
+ * If <code>state</code> has this value, <code>currentSegment</code>
+ * will emit a <code>SEG_MOVETO</code> 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
+ * <code>EMIT_SEGMENT</code>, <code>EMIT_CLOSE</code>, or
+ * <code>EMIT_MOVETO</code>.
+ */
+ 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.
+ *
+ * <p><img src="doc-files/ZonePathIterator-1.png" width="426"
+ * height="194" alt="An example curve" /></p>
+ *
+ * <p>If <code>cur</code> is an on-curve point, the returned segment
+ * is a straight line to <code>cur</code>. In the illustration, this
+ * would be the case for <code>cur = 4</code>.</p>
+ *
+ * <p>If <code>cur</code> is an off-curve point, and
+ * <code>cur</code>&#x2019;s successor <code>succ</code> is also
+ * off-curve, the returned segment is a quadratic B&eacute;zier
+ * spline whose control point is <code>cur</code>, and whose end
+ * point is located at the middle of the line connecting
+ * <code>cur</code> and <code>succ</code>. In the illustration,
+ * this would be the case for <code>cur = 5</code>.</p>
+ *
+ * <p>If <code>cur</code> is an off-curve point, and
+ * <code>cur</code>&#x2019;s successor <code>succ</code> is
+ * on-curve, the returned segment is a quadratic B&eacute;zier
+ * spline whose control point is <code>cur</code>, and whose end
+ * point is <code>succ</code>. In the illustration, this would
+ * be the case for <code>cur = 6</code>.</p>
+ *
+ * @return either <code>PathIterator.SEG_LINETO</code> or
+ * <code>PathIterator.SEG_QUADTO</code>.
+ */
+ 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.
+ *
+ * <p>If the contour starts with an on-curve point, the returned
+ * segment is a <code>SEG_MOVETO</code> to that point.</p>
+ *
+ * <p>If the contour starts with an off-curve point, and the contour
+ * ends with an on-curve point, the returned segment is a
+ * <code>SEG_MOVETO</code> to the end point.</p>
+ *
+ * <p>If the contour starts with an off-curve point, and the contour
+ * also ends with an off-curve point, the returned segment is a
+ * <code>SEG_MOVETO</code> to the location at the middle between the
+ * start and end points of the contour.</p>
+ *
+ * @return <code>PathIterator.SEG_MOVETO</code>.
+ */
+ 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
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/doc-files/ZonePathIterator-1.dia
Binary files 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
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/doc-files/ZonePathIterator-1.png
Binary files 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 <code>null</code>
+ * 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 <code>null</code>.
+ *
+ * @return the real image source, or <code>null</code> 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<ImageObserver> observers;
+
+ private volatile boolean complete = false;
+
+ /**
+ * Creates a new AsyncImage.
+ */
+ AsyncImage()
+ {
+ observers = new HashSet<ImageObserver>();
+ }
+
+ 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<ImageObserver> 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 <code>null</code>. 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: <br/>
+ * 1. if no color model was given use the hinted color model <br/>
+ * 2. if no color model was given and non was hinted use the default sRGB color model. <br/>
+ * Also:<br/>
+ * 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.awt.image package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.awt.image</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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.
+ *
+ * <h2>Backend interface</h2>
+ * <p>
+ * 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.
+ * </p>
+ * <p>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.</p>
+ * <p>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.</p>
+ * <p>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.</p>
+ *
+ * <h2>Acceleration options</h2>
+ * <p>
+ * The fact that it is
+ * pure Java makes it a little slow. However, there are several ways of
+ * accelerating the rendering pipeline:
+ * <ol>
+ * <li><em>Optimization hooks for AWT 1.1 - like graphics operations.</em>
+ * The most important methods from the {@link java.awt.Graphics} class
+ * have a corresponding <code>raw*</code> 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.</li>
+ * <li><em>Native PaintContexts and CompositeContext.</em> 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.</li>
+ * <li>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.</li>
+ * </ol>
+ * </p>
+ *
+ * @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<Image, HashMap<Dimension,Image>> imageCache =
+ new WeakHashMap<Image, HashMap<Dimension, Image>>();
+
+ /**
+ * 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<ScanlineConverter> scanlineConverters =
+ new LinkedList<ScanlineConverter>();
+
+ /**
+ * Caches glyph vectors for better drawing performance.
+ */
+ private static final Map<TextCacheKey,GlyphVector> gvCache =
+ Collections.synchronizedMap(new LRUCache<TextCacheKey,GlyphVector>(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<Key, Object> STANDARD_HINTS;
+ static
+ {
+
+ HashMap<Key, Object> hints = new HashMap<Key, Object>();
+ 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 <code>areaOfInterest</code>.
+ *
+ * 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 <code>areaOfInterest</code>
+ * 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 <code>areaOfInterest</code> 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 <code>theta</code> 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 <code>theta</code> 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 <code>scaleX</code> and
+ * <code>scaleY</code>.
+ *
+ * @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 <code>shearX</code> and
+ * <code>shearY</code>.
+ *
+ * @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
+ * <code>t</code>.
+ *
+ * @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 <code>f == null</code>, 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 <code>clip</code>.
+ *
+ * @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 <code>true</code> 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 <code>true</code> when the image is painted completely,
+ * <code>false</code> 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 <code>rect</code>. 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
+ * <code>rect</code>.
+ *
+ * @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<Dimension,Image> 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<Dimension,Image>();
+ 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 <code>i</code>.
+ *
+ * @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 <code>y</code>
+ * and using the coverage information in <code>sc</code>.
+ *
+ * @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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.awt package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.awt</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 <neugens@limasoftware.net>
+ */
+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.
+ *
+ * <p><b>State kept by the peer:</b> 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}.</p>
+ *
+ * <p><b>Thread Safety:</b> Methods of this interface may be called
+ * from arbitrary threads at any time. Implementations of the
+ * <code>ClasspathFontPeer</code> interface are required to perform
+ * the necessary synchronization.</p>
+ *
+ * @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<K,V> extends LinkedHashMap<K,V>
+ {
+ 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<AffineTransform,TransformAttribute> transCache =
+ new LRUCache<AffineTransform,TransformAttribute>(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
+ * <i>&#x201c;Light&#x201d;</i>.
+ *
+ * <p>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
+ * <code>locale</code> is <code>null</code>, the returned name is
+ * localized to the user&#x2019;s default locale.
+ *
+ * @return the name of the face inside its family, or
+ * <code>null</code> 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.
+ *
+ * <p>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
+ * <code>javax.print</code> package.
+ *
+ * <p><b>Names are not unique:</b> 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.</p>
+ *
+ * <p>This situation would occur for an OpenType or TrueType font
+ * that has a <code>post</code> table of format 3 and provides a
+ * mapping from glyph IDs to Unicode sequences through a
+ * <code>Zapf</code> 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 <code>null</code> 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 <neugens@limasoftware.net>
+ */
+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 <neugens@limasoftware.net>
+ */
+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<ImageConsumer> consumers;
+
+ NullImageSource()
+ {
+ consumers = new ArrayList<ImageConsumer>();
+ }
+
+ 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<ImageObserver> observers;
+
+ /**
+ * Creates a new AsyncImage that loads from the specified URL.
+ */
+ AsyncImage(URL url)
+ {
+ observers = new HashSet<ImageObserver>();
+ 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<ImageObserver> 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<BufferedImage, CairoSurface> bufferedImages
+ = new WeakHashMap<BufferedImage, CairoSurface>();
+
+ /**
+ * 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<RenderingHints.Key, Object> getDefaultHints()
+ {
+ HashMap<RenderingHints.Key, Object> defaultHints =
+ new HashMap<RenderingHints.Key, Object>();
+
+ 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<Integer> hasLock = new ThreadLocal<Integer>();
+ 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<String,TextLayout> textLayoutCache = new GtkToolkit.LRUCache<String,TextLayout>(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<Integer,GlyphMetrics> 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<Integer,GlyphMetrics>();
+ setupMetrics();
+ }
+
+ public GdkFontPeer (String name, Map attributes)
+ {
+ super(name, attributes);
+ initState ();
+ setFont (this.familyName, this.style, (int)this.size);
+ metricsCache = new HashMap<Integer,GlyphMetrics>();
+ 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&#x2019;s name table.
+ *
+ * @param name the numeric TrueType or OpenType name ID.
+ *
+ * @param locale the locale for which names shall be localized, or
+ * <code>null</code> 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<String> mimeTypes = new ArrayList<String>();
+ public ArrayList<String> extensions = new ArrayList<String>();
+
+ 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<ImageFormatSpec> imageFormatSpecs;
+
+ public static ImageFormatSpec registerFormat(String name, boolean writable)
+ {
+ ImageFormatSpec ifs = new ImageFormatSpec(name, writable);
+ synchronized(GdkPixbufDecoder.class)
+ {
+ if (imageFormatSpecs == null)
+ imageFormatSpecs = new ArrayList<ImageFormatSpec>();
+ imageFormatSpecs.add(ifs);
+ }
+ return ifs;
+ }
+
+ static String[] getFormatNames(boolean writable)
+ {
+ ArrayList<String> names = new ArrayList<String>();
+ synchronized (imageFormatSpecs)
+ {
+ Iterator<ImageFormatSpec> 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<String> j = ifs.extensions.iterator();
+ while (j.hasNext())
+ names.add(j.next());
+ }
+ }
+ return names.toArray(new String[names.size()]);
+ }
+
+ static String[] getFormatExtensions(boolean writable)
+ {
+ ArrayList<String> extensions = new ArrayList<String>();
+ synchronized (imageFormatSpecs)
+ {
+ Iterator<ImageFormatSpec> i = imageFormatSpecs.iterator();
+ while (i.hasNext())
+ {
+ ImageFormatSpec ifs = i.next();
+ if (writable && !ifs.writable)
+ continue;
+ Iterator<String> j = ifs.extensions.iterator();
+ while (j.hasNext())
+ extensions.add(j.next());
+ }
+ }
+ return extensions.toArray(new String[extensions.size()]);
+ }
+
+ static String[] getFormatMimeTypes(boolean writable)
+ {
+ ArrayList<String> mimeTypes = new ArrayList<String>();
+ synchronized (imageFormatSpecs)
+ {
+ Iterator<ImageFormatSpec> i = imageFormatSpecs.iterator();
+ while (i.hasNext())
+ {
+ ImageFormatSpec ifs = i.next();
+ if (writable && !ifs.writable)
+ continue;
+ Iterator<String> 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<ImageFormatSpec> i = imageFormatSpecs.iterator();
+ while (i.hasNext())
+ {
+ ImageFormatSpec ifs = i.next();
+
+ if (needWritable && !ifs.writable)
+ continue;
+
+ if (ifs.name.equals(str))
+ return str;
+
+ Iterator<String> 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<Object> data = new ArrayList<Object>();
+
+ /**
+ * 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<ImageTypeSpecifier> getImageTypes(int imageIndex)
+ throws IOException
+ {
+ BufferedImage img = getBufferedImage();
+ Vector<ImageTypeSpecifier> vec = new Vector<ImageTypeSpecifier>();
+ 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 <code>GdkGraphicsEnvironment</code> instance that created this
+ * <code>GdkScreenGraphicsDevice</code>. 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 <code>GdkScreenGraphicsDevice</code>.
+ * If the array is <code>null</code> <code>nativeGetDisplayModes</code> has
+ * to be called.
+ */
+ X11DisplayMode[] displayModes;
+
+ /** The non-changeable display mode of this <code>GdkScreenGraphicsDevice
+ * </code>. This field gets initialized by the {@link #init()} method. If it
+ * is still <code>null</code> 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<DisplayMode> list = new ArrayList<DisplayMode>();
+ for(int i=0;i<displayModes.length;i++)
+ for(int j=0;j<displayModes[i].rates.length;j++)
+ list.add(new DisplayMode(displayModes[i].width,
+ displayModes[i].height,
+ DisplayMode.BIT_DEPTH_MULTI,
+ displayModes[i].rates[j]));
+
+ return list.toArray(new DisplayMode[list.size()]);
+ }
+
+ native X11DisplayMode[] nativeGetDisplayModes(GdkGraphicsEnvironment env);
+
+ /**
+ * Real fullscreen exclusive mode is not supported.
+ *
+ * @return <code>false</code>
+ * @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<displayModes.length; i++)
+ if (displayModes[i].width == dm.getWidth()
+ && displayModes[i].height == dm.getHeight())
+ {
+ synchronized (this)
+ {
+ nativeSetDisplayMode(env,
+ i,
+ (short) dm.getRefreshRate());
+
+ bounds = null;
+ }
+
+ return;
+ }
+
+ throw new IllegalArgumentException("Mode not supported by this device.");
+ }
+
+ native void nativeSetDisplayMode(GdkGraphicsEnvironment env,
+ int index, short rate);
+
+ /** A class that simply encapsulates the X11 display mode data.
+ */
+ static class X11DisplayMode
+ {
+ short[] rates;
+ int width;
+ int height;
+
+ X11DisplayMode(int width, int height, short[] rates)
+ {
+ this.width = width;
+ this.height = height;
+ this.rates = rates;
+ }
+
+ }
+
+ public void setFullScreenWindow(Window w)
+ {
+ // Bring old fullscreen window back into its original state.
+ if (fullscreenWindow != null && w != fullscreenWindow)
+ {
+ if (fullscreenWindow instanceof Frame)
+ {
+ // Decoration state can only be switched when the peer is
+ // non-existent. That means we have to dispose the
+ // Frame.
+ Frame f = (Frame) fullscreenWindow;
+ if (oldWindowDecorationState != f.isUndecorated())
+ {
+ f.dispose();
+ f.setUndecorated(oldWindowDecorationState);
+ }
+ }
+
+ fullscreenWindow.setBounds(oldWindowBounds);
+
+ if (!fullscreenWindow.isVisible())
+ fullscreenWindow.setVisible(true);
+ }
+
+ // If applicable remove decoration, then maximize the window and
+ // bring it to the foreground.
+ if (w != null)
+ {
+ if (w instanceof Frame)
+ {
+ Frame f = (Frame) w;
+ oldWindowDecorationState = f.isUndecorated();
+ if (!oldWindowDecorationState)
+ {
+ f.dispose();
+ f.setUndecorated(true);
+ }
+ }
+
+ oldWindowBounds = w.getBounds();
+
+ DisplayMode dm = getDisplayMode();
+
+ w.setBounds(0, 0, dm.getWidth(), dm.getHeight());
+
+ if (!w.isVisible())
+ w.setVisible(true);
+
+ w.requestFocus();
+ w.toFront();
+
+ }
+
+ fullscreenWindow = w;
+ }
+
+ public Window getFullScreenWindow()
+ {
+ return fullscreenWindow;
+ }
+
+ Rectangle getBounds()
+ {
+ synchronized(this)
+ {
+ if (bounds == null)
+ bounds = nativeGetBounds();
+ }
+
+ return bounds;
+ }
+
+ native Rectangle nativeGetBounds();
+
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkButtonPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkButtonPeer.java
new file mode 100644
index 000000000..6ff56c0f2
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkButtonPeer.java
@@ -0,0 +1,93 @@
+/* GtkButtonPeer.java -- Implements ButtonPeer with GTK
+ Copyright (C) 1998, 1999, 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.gtk;
+
+import java.awt.Button;
+import java.awt.event.ActionEvent;
+import java.awt.peer.ButtonPeer;
+
+// A composite widget. GtkButtons have transparent backgrounds. An
+// AWT Button is opaque. To compensate, a GtkButtonPeer is a
+// GtkButton packed in a GtkEventBox.
+public class GtkButtonPeer extends GtkComponentPeer
+ implements ButtonPeer
+{
+ native void create (String label);
+
+ public native void connectSignals ();
+
+ /**
+ * Overridden to set Font of Label inside Button inside EventBox.
+ */
+ protected native void gtkWidgetModifyFont(String name, int style, int size);
+ native void gtkSetLabel (String label);
+ native void gtkWidgetSetForeground (int red, int green, int blue);
+ native void gtkWidgetSetBackground (int red, int green, int blue);
+ native void gtkActivate ();
+ native void gtkWidgetRequestFocus ();
+ native void setNativeBounds (int x, int y, int width, int height);
+
+ // Because this is a composite widget, we need to retrieve the
+ // GtkButton's preferred dimensions, not the enclosing
+ // GtkEventBox's.
+ native void gtkWidgetGetPreferredDimensions (int[] dim);
+
+ public GtkButtonPeer (Button b)
+ {
+ super (b);
+ }
+
+ void create ()
+ {
+ create (((Button) awtComponent).getLabel ());
+ }
+
+ public void setLabel (String label)
+ {
+ gtkSetLabel(label);
+ }
+
+ void postActionEvent (int mods)
+ {
+ q().postEvent (new ActionEvent (awtWidget,
+ ActionEvent.ACTION_PERFORMED,
+ ((Button) awtComponent).getActionCommand (),
+ mods));
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCanvasPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCanvasPeer.java
new file mode 100644
index 000000000..30c39dede
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCanvasPeer.java
@@ -0,0 +1,60 @@
+/* GtkCanvasPeer.java
+ Copyright (C) 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.awt.peer.gtk;
+
+import java.awt.Canvas;
+import java.awt.Dimension;
+import java.awt.peer.CanvasPeer;
+
+public class GtkCanvasPeer extends GtkComponentPeer implements CanvasPeer
+{
+ native void create ();
+
+ public GtkCanvasPeer (Canvas c)
+ {
+ super (c);
+ }
+
+ // Preferred size for a drawing widget is always what the user
+ // requested.
+ public Dimension preferredSize()
+ {
+ return awtComponent.getSize();
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java
new file mode 100644
index 000000000..be9247e8d
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java
@@ -0,0 +1,74 @@
+/* GtkCheckboxMenuItemPeer.java -- Implements CheckboxMenuItemPeer 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.CheckboxMenuItem;
+import java.awt.ItemSelectable;
+import java.awt.event.ItemEvent;
+import java.awt.peer.CheckboxMenuItemPeer;
+
+public class GtkCheckboxMenuItemPeer extends GtkMenuItemPeer
+ implements CheckboxMenuItemPeer
+{
+ protected native void create (String label);
+
+ public GtkCheckboxMenuItemPeer (CheckboxMenuItem menu)
+ {
+ super (menu);
+ setState (menu.getState ());
+ }
+
+ public native void setState(boolean t);
+
+ /**
+ * Called from the signal handler of the gtk widget. Posts a
+ * ItemEvent to indicate a state changed, then calls super to post
+ * an ActionEvent.
+ */
+ protected void postMenuActionEvent ()
+ {
+ CheckboxMenuItem item = (CheckboxMenuItem)awtWidget;
+ q().postEvent (new ItemEvent ((ItemSelectable)awtWidget,
+ ItemEvent.ITEM_STATE_CHANGED,
+ item.getActionCommand(),
+ item.getState() ? ItemEvent.DESELECTED : ItemEvent.SELECTED));
+
+ super.postMenuActionEvent();
+ }
+}
diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java
new file mode 100644
index 000000000..6321bc64d
--- /dev/null
+++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java
@@ -0,0 +1,255 @@
+/* GtkCheckboxPeer.java -- Implements CheckboxPeer with GTK
+ Copyright (C) 1998, 1999, 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.awt.peer.gtk;
+
+import java.awt.Checkbox;
+import java.awt.CheckboxGroup;
+import java.awt.event.ItemEvent;
+import java.awt.peer.CheckboxPeer;
+import java.util.WeakHashMap;
+
+/**
+ * This class wraps either a GtkCheckButton or a GtkOptionButton
+ * depending on if this peer's owner belongs to a CheckboxGroup.
+ */
+public class GtkCheckboxPeer extends GtkComponentPeer
+ implements CheckboxPeer
+{
+ // The CheckboxGroup to which this GtkCheckboxPeer's owner belongs.
+ public CheckboxGroup current_group;
+ // The current state of the GTK checkbox.
+ private boolean currentState;
+
+ // A map from CheckboxGroup to GSList* GTK option group pointer.
+ private static WeakHashMap<CheckboxGroup,Long> groupMap
+ = new WeakHashMap<CheckboxGroup,Long>();
+
+ 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 <code>true</code> if the component is a direct (== no intermediate
+ * heavyweights) lightweight descendant of this peer's component.
+ *
+ * @param c the component to check
+ *
+ * @return <code>true</code> 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<ImageObserver> 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<ImageObserver>();
+ 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<String,Object>();
+ 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<String,Object>();
+ }
+
+ /**
+ * 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<String,Object>();
+ errorLoading = false;
+ }
+
+ /**
+ * Constructs a GtkImage from a URL. May result in an error image.
+ */
+ public GtkImage (URL url)
+ {
+ isLoaded = false;
+ observers = new Vector<ImageObserver>();
+ 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<String,Object>();
+ }
+
+ /**
+ * 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<String,Object>();
+ 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<String,Object>();
+ }
+
+ /**
+ * 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<String,Object>();
+ 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<String,Object>();
+
+ 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<ImageObserver>();
+ 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 <code>create()</code> that needs to be
+ * overridden by subclasses, to create the MenuComponent. It will
+ * then correctly setup the font for the component based on the
+ * component and/or its containing parent component.
+ */
+ public GtkMenuComponentPeer(MenuComponent component)
+ {
+ super(component);
+ create();
+ setFont();
+ }
+
+ /**
+ * Removes the awtWidget components from the native state tables.
+ * Subclasses should call <code>super.dispose()</code> if they don't
+ * remove these themselves.
+ */
+ public native void dispose();
+
+ /**
+ * Sets the font for this particular MenuComponent only (not any
+ * containing items, if any).
+ */
+ public void setFont(Font font)
+ {
+ 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<File> 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<DataFlavor> flavorsList =
+ new ArrayList<DataFlavor>(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<File> getURIs()
+ {
+ List<File> 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<File> list = new ArrayList<File>(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<File> 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<K,V> extends LinkedHashMap<K,V>
+ {
+ 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<Map,ClasspathFontPeer> fontCache =
+ new LRUCache<Map,ClasspathFontPeer>(50);
+ private LRUCache<Object,Image> imageCache = new LRUCache<Object,Image>(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<TextAttribute,Object> attrs = new HashMap<TextAttribute,Object>();
+ 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<Object,Object> keyMap = new HashMap<Object,Object>(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 extends DragGestureRecognizer> T
+ createDragGestureRecognizer(Class<T> 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<TextAttribute,?> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.awt.peer.gtk package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.awt.peer.gtk</title></head>
+
+<body>
+<p>This package implements the GTK peer for java.awt.</p>
+
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.awt.peer package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.awt.peer</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 <code>true</code> if the button is currently showing,
+ * <code>false</code> 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
+ * <code>processMouseEvent()</code> after having retargetted it to this
+ * button.
+ *
+ * @param ev the mouse event
+ */
+ public void handleMouseEvent(MouseEvent ev)
+ {
+ ev.setSource(this);
+ processMouseEvent(ev);
+ }
+
+ /**
+ * Handles mouse motion events by forwarding it to
+ * <code>processMouseMotionEvent()</code> after having retargetted it to
+ * this button.
+ *
+ * @param ev the mouse motion event
+ */
+ public void handleMouseMotionEvent(MouseEvent ev)
+ {
+ ev.setSource(this);
+ processMouseMotionEvent(ev);
+ }
+
+ /**
+ * Handles key events by forwarding it to
+ * <code>processKeyEvent()</code> after having retargetted it to this
+ * button.
+ *
+ * @param ev the mouse event
+ */
+ public void handleKeyEvent(KeyEvent ev)
+ {
+ ev.setSource(this);
+ processKeyEvent(ev);
+ }
+
+ public Container getParent()
+ {
+ Container par = null;
+ if (button != null)
+ par = button.getParent();
+ return par;
+ }
+
+ /**
+ * Handles focus events by forwarding it to
+ * <code>processFocusEvent()</code>.
+ *
+ * @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 <code>SwingCanvasPeer</code> 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 <code>this</code>
+ */
+ public JComponent getJComponent()
+ {
+ return this;
+ }
+
+ /**
+ * Handles mouse events by forwarding it to
+ * <code>processMouseEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleMouseEvent(MouseEvent ev)
+ {
+ ev.setSource(this);
+ processMouseEvent(ev);
+ }
+
+ /**
+ * Handles mouse motion events by forwarding it to
+ * <code>processMouseMotionEvent()</code>.
+ *
+ * @param ev the mouse motion event
+ */
+ public void handleMouseMotionEvent(MouseEvent ev)
+ {
+ ev.setSource(this);
+ processMouseMotionEvent(ev);
+ }
+
+ /**
+ * Handles key events by forwarding it to <code>processKeyEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleKeyEvent(KeyEvent ev)
+ {
+ ev.setSource(this);
+ processKeyEvent(ev);
+ }
+
+ /**
+ * Handles focus events by forwarding it to
+ * <code>processFocusEvent()</code>.
+ *
+ * @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 <code>true</code> if the button is currently showing,
+ * <code>false</code> 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 <code>width</code> and
+ * <code>height</code>.
+ *
+ * This is implemented to let the parent component create the image. This
+ * eventually goes up to the top-level component peer, which is then expected
+ * to deliver the image.
+ *
+ * @param width the width of the image to be created
+ * @param height the height of the image to be created
+ *
+ * @return the created image
+ */
+ public Image createImage(int width, int height)
+ {
+ Component parent = awtComponent.getParent();
+ ComponentPeer parentPeer = parent.getPeer();
+ return parentPeer.createImage(width, height);
+ }
+
+ /**
+ * Disables the component. This is called by {@link Component#disable()}.
+ */
+ public void disable()
+ {
+ if (swingComponent != null)
+ swingComponent.getJComponent().setEnabled(false);
+ }
+
+ /**
+ * Disposes the component peer. This should release all resources held by the
+ * peer. This is called when the component is no longer in use.
+ */
+ public void dispose()
+ {
+ // 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 <code>true</code> if the component can receive keyboard input
+ * focus. This is called from {@link Component#isFocusTraversable()}.
+ *
+ * This is implemented to return isFocusable() from the Swing component.
+ *
+ * @specnote Part of the earlier 1.1 API, replaced by isFocusable().
+ */
+ public boolean isFocusTraversable()
+ {
+ return swingComponent != null ?
+ swingComponent.getJComponent().isFocusable() : false;
+ }
+
+ /**
+ * Returns <code>true</code> if the component can receive keyboard input
+ * focus. This is called from {@link Component#isFocusable()}.
+ *
+ * This is implemented to return isFocusable() from the Swing component.
+ */
+ public boolean isFocusable()
+ {
+ return swingComponent != null ?
+ swingComponent.getJComponent().isFocusable() : false;
+ }
+
+ /**
+ * Returns the minimum size for the component. This is called by
+ * {@link Component#minimumSize()}.
+ *
+ * This is implemented to return the Swing component's minimum size.
+ *
+ * @return the minimum size for the component
+ */
+ public Dimension minimumSize()
+ {
+ Dimension retVal;
+ if (swingComponent != null)
+ retVal = swingComponent.getJComponent().getMinimumSize();
+ else
+ retVal = new Dimension(0, 0);
+ return retVal;
+ }
+
+ /**
+ * Returns the preferred size for the component. This is called by
+ * {@link Component#getPreferredSize()}.
+ *
+ * This is implemented to return the Swing component's preferred size.
+ *
+ * @return the preferred size for the component
+ */
+ public Dimension preferredSize()
+ {
+ Dimension retVal;
+ if (swingComponent != null)
+ retVal = swingComponent.getJComponent().getPreferredSize();
+ else
+ retVal = new Dimension(0, 0);
+ return retVal;
+ }
+
+ /**
+ * 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 <code>true</code> if the image has been fully prepared,
+ * <code>false</code> otherwise (in which case the image observer
+ * receives updates)
+ */
+ public boolean prepareImage(Image img, int width, int height, ImageObserver ob)
+ {
+ Component parent = awtComponent.getParent();
+ 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 <code>true</code> to enable the component,
+ * <code>false</code> to disable it
+ */
+ public void setEnabled(boolean enabled)
+ {
+ if (swingComponent != null)
+ swingComponent.getJComponent().setEnabled(enabled);
+ }
+
+ /**
+ * Sets the font of the component. This is called by
+ * {@link Component#setFont(Font)}.
+ *
+ * This is implemented to call setFont() on the Swing component.
+ *
+ * @param font the font to set
+ */
+ public void setFont(Font font)
+ {
+ 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 <code>true</code> to make the component visible,
+ * <code>false</code> 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 <code>true</code> if this component has been obscured,
+ * <code>false</code> otherwise. This will only work if
+ * {@link #canDetermineObscurity()} also returns <code>true</code>.
+ *
+ * This is not yet implemented.
+ *
+ * @return <code>true</code> if this component has been obscured,
+ * <code>false</code> otherwise.
+ */
+ public boolean isObscured()
+ {
+ return false;
+ }
+
+ /**
+ * Returns <code>true</code> if this component peer can determine if the
+ * component has been obscured, <code>false</code> otherwise.
+ *
+ * This is not yet implemented.
+ *
+ * @return <code>true</code> if this component peer can determine if the
+ * component has been obscured, <code>false</code> otherwise
+ */
+ public boolean canDetermineObscurity()
+ {
+ return false;
+ }
+
+ /**
+ * Coalesces the specified paint event.
+ *
+ * @param e the paint event
+ */
+ public void coalescePaintEvent(PaintEvent e)
+ {
+ 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,
+ * <code>false</code> otherwise.
+ *
+ * This is not yet implemented and returns <code>false</code>.
+ *
+ * @return true, if this component can handle wheel scrolling,
+ * <code>false</code> otherwise
+ */
+ public boolean handlesWheelScrolling()
+ {
+ return false;
+ }
+
+ /**
+ * A convenience method that creates a volatile image. The volatile
+ * image is created on the screen device on which this component is
+ * displayed, in the device's current graphics configuration.
+ *
+ * This is implemented to let the parent component peer create an image.
+ * This eventually ends up in the toplevel component peer, which is then
+ * responsible for creating the real image.
+ *
+ * @param width width of the image
+ * @param height height of the image
+ *
+ * @see VolatileImage
+ *
+ * @since 1.2
+ */
+ public VolatileImage createVolatileImage(int width, int height)
+ {
+ Component parent = awtComponent.getParent();
+ 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 <code>false</code> unconditionally. This method is not used at
+ * the moment.
+ *
+ * @return <code>false</code>
+ */
+ public boolean isPaintPending()
+ {
+ return false;
+ }
+
+ /**
+ * Returns <code>false</code> unconditionally. This method is not used at
+ * the moment.
+ *
+ * @return <code>false</code>
+ */
+ public boolean isRestackSupported()
+ {
+ return false;
+ }
+
+ /**
+ * This method is not used at the moment.
+ */
+ public void cancelPendingPaint(int x, int y, int width, int height)
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * This method is not used at the moment.
+ */
+ public void restack()
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * 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:
+ * <ul>
+ * <li>{@link ComponentPeer#getLocationOnScreen()}</li>
+ * <li>{@link ComponentPeer#getGraphics()}</li>
+ * <li>{@link ComponentPeer#createImage(int, int)}</li>
+ * </ul>
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public abstract class SwingFramePeer
+ extends SwingWindowPeer
+ implements FramePeer
+{
+ /**
+ * The menu bar to display.
+ */
+ SwingMenuBarPeer menuBar = null;
+
+ /**
+ * Creates a new SwingFramePeer.
+ *
+ * @param frame the frame
+ */
+ public SwingFramePeer(Frame frame)
+ {
+ super(frame);
+ }
+
+ /**
+ * Sets the menu bar to display in this frame.
+ *
+ * @param mb the menu bar to set
+ */
+ public void setMenuBar(MenuBar mb)
+ {
+ menuBar = (SwingMenuBarPeer) mb.getPeer();
+ menuBar.setFramePeer(this);
+ menuBar.setWidth(awtComponent.getWidth());
+ }
+
+ /**
+ * Triggers 'heavyweight' painting of the frame. This will paint a menu bar
+ * if present as well as the child components of this frame.
+ *
+ * @param g the graphics context to use for painting
+ */
+ protected void 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 <code>this</code>
+ */
+ public JComponent getJComponent()
+ {
+ return this;
+ }
+
+ /**
+ * Handles mouse events by forwarding it to
+ * <code>processMouseEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleMouseEvent(MouseEvent ev)
+ {
+ processMouseEvent(ev);
+ }
+
+ /**
+ * Handles mouse motion events by forwarding it to
+ * <code>processMouseMotionEvent()</code>.
+ *
+ * @param ev the mouse motion event
+ */
+ public void handleMouseMotionEvent(MouseEvent ev)
+ {
+ processMouseMotionEvent(ev);
+ }
+
+ /**
+ * Handles key events by forwarding it to <code>processKeyEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleKeyEvent(KeyEvent ev)
+ {
+ processKeyEvent(ev);
+ }
+
+ /**
+ * Handles focus events by forwarding it to
+ * <code>processFocusEvent()</code>.
+ *
+ * @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 <code>true</code> if the button is currently showing,
+ * <code>false</code> 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 <code>SwingLabelPeer</code> 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 <code>this</code>
+ */
+ public JComponent getJComponent()
+ {
+ return this;
+ }
+
+ /**
+ * Handles mouse events by forwarding it to
+ * <code>processMouseEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleMouseEvent(MouseEvent ev)
+ {
+ ev.setSource(this);
+ dispatchEvent(ev);
+ }
+
+ /**
+ * Force lightweight mouse dispatching.
+ */
+ public boolean isLightweight()
+ {
+ return false;
+ }
+
+ /**
+ * Handles mouse motion events by forwarding it to
+ * <code>processMouseMotionEvent()</code>.
+ *
+ * @param ev the mouse motion event
+ */
+ public void handleMouseMotionEvent(MouseEvent ev)
+ {
+ processMouseMotionEvent(ev);
+ }
+
+ /**
+ * Handles key events by forwarding it to <code>processKeyEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleKeyEvent(KeyEvent ev)
+ {
+ processKeyEvent(ev);
+ }
+
+ /**
+ * Handles focus events by forwarding it to <code>processFocusEvent()</code>.
+ *
+ * @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 <code>true</code> if the button is currently showing,
+ * <code>false</code> 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 <code>true</code>, since we assume that when the
+ * menubar has a peer, it must be showing.
+ *
+ * @return <code>true</code>
+ */
+ public boolean isShowing()
+ {
+ // FIXME: This might be wrong. Maybe find a better way to do that.
+ return true;
+ }
+
+ /**
+ * Handles mouse events by forwarding it to
+ * <code>processMouseEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleMouseEvent(MouseEvent ev)
+ {
+ ev.setSource(this);
+ processMouseEvent(ev);
+ }
+
+ /**
+ * Determines the menubar's screen location by asking the SwingFramePeer
+ * for it.
+ *
+ * @return the screen location of the menu bar
+ */
+ public Point getLocationOnScreen()
+ {
+ return framePeer.getMenuLocationOnScreen();
+ }
+ }
+
+ /**
+ * Creates a new <code>SwingMenuBarPeer</code> instance.
+ *
+ * @param awtMenuBar the AWT menu bar
+ */
+ public SwingMenuBarPeer(MenuBar awtMenuBar)
+ {
+ this.awtMenuBar = awtMenuBar;
+ menuBar = new SwingMenuBar();
+ menuBar.setDoubleBuffered(false);
+ // Add all the menus that are already in the MenuBar.
+ for (int i = 0; i < awtMenuBar.getMenuCount(); i++)
+ {
+ Menu menu = awtMenuBar.getMenu(i);
+ menu.addNotify();
+ addMenu(awtMenuBar.getMenu(i));
+ }
+ }
+
+ /**
+ * Sets the <code>SwingFramePeer</code> of the frame that holds this menu.
+ *
+ * @param peer the <code>SwingFramePeer</code> to set
+ */
+ public void setFramePeer(SwingFramePeer peer)
+ {
+ framePeer = peer;
+ }
+
+ /**
+ * Adds a menu to the menu bar.
+ *
+ * @param m the menu to add
+ */
+ public void addMenu(Menu m)
+ {
+ SwingMenuPeer menuPeer = (SwingMenuPeer) m.getPeer();
+ menuBar.add(menuPeer.menu);
+ }
+
+ /**
+ * Adds a help menu to the menu bar.
+ *
+ * @param 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 <code>SwingMenuItemPeer</code>.
+ *
+ * @param awtMenuItem the AWT menu item
+ */
+ public SwingMenuItemPeer(MenuItem awtMenuItem)
+ {
+ this.awtMenuItem = awtMenuItem;
+ menuItem = new JMenuItem(awtMenuItem.getLabel());
+ menuItem.addActionListener(new SwingMenuItemListener());
+ }
+
+ /**
+ * Disables the menu item.
+ */
+ public void disable()
+ {
+ menuItem.setEnabled(false);
+ }
+
+ /**
+ * Enables the menu item.
+ */
+ public void enable()
+ {
+ menuItem.setEnabled(true);
+ }
+
+ /**
+ * Sets the enabled state to <code>enabled</code>.
+ *
+ * @param enabled if the menu item should be enabled or not
+ */
+ public void setEnabled(boolean enabled)
+ {
+ menuItem.setEnabled(enabled);
+ }
+
+ /**
+ * Sets the label for the menu item.
+ *
+ * @param text the label to set
+ */
+ public void setLabel(String text)
+ {
+ menuItem.setText(text);
+ }
+
+ /**
+ * Disposes the menu item. This releases any reference to the Swing and AWT
+ * menu item.
+ */
+ public void dispose()
+ {
+ menuItem = null;
+ awtMenuItem = null;
+ }
+
+ /**
+ * Sets the font for this menu item.
+ *
+ * @param font the font to set
+ */
+ public void setFont(Font font)
+ {
+ menuItem.setFont(font);
+ }
+
+}
diff --git a/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 <code>true</code>, since we assume that when the
+ * menu has a peer, it must be showing.
+ *
+ * @return <code>true</code>
+ */
+ public boolean isShowing()
+ {
+ // FIXME: This might be wrong. Maybe find a better way to do that.
+ return true;
+ }
+
+ /**
+ * Overridden so that we can provide a location even without a real peer
+ * attached.
+ *
+ * @return the screen location of this menu
+ */
+ public Point getLocationOnScreen()
+ {
+ Point parentLoc = getParent().getLocationOnScreen();
+ parentLoc.x += getX();
+ parentLoc.y += getY();
+ return parentLoc;
+ }
+
+ /**
+ * Handles mouse events by forwarding them to
+ * <code>processMouseEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleMouseEvent(MouseEvent ev)
+ {
+ ev.setSource(this);
+ processMouseEvent(ev);
+ }
+
+ /**
+ * Handles mouse events by forwarding them to
+ * <code>processMouseMotionEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleMouseMotionEvent(MouseEvent ev)
+ {
+ ev.setSource(this);
+ processMouseMotionEvent(ev);
+ }
+ }
+
+ /**
+ * Creates a new <code>SwingMenuPeer</code> instance.
+ *
+ * @param awtMenu the AWT menu
+ */
+ public SwingMenuPeer(Menu awtMenu)
+ {
+ this.awtMenu = awtMenu;
+ menu = new SwingMenu();
+ menu.setDoubleBuffered(false);
+ menu.setText(awtMenu.getLabel());
+ for (int i = 0; i < awtMenu.getItemCount(); i++)
+ {
+ MenuItem item = awtMenu.getItem(i);
+ item.addNotify();
+ SwingMenuItemPeer peer = (SwingMenuItemPeer) item.getPeer();
+ menu.add(peer.menuItem);
+ }
+ }
+
+ /**
+ * Adds a menu item to this menu.
+ *
+ * @param item the menu item to add
+ */
+ public void addItem(MenuItem item)
+ {
+ SwingMenuItemPeer menuItemPeer = (SwingMenuItemPeer) item.getPeer();
+ menu.add(menuItemPeer.menuItem);
+ }
+
+ /**
+ * Adds a separator to the menu.
+ */
+ public void addSeparator()
+ {
+ menu.addSeparator();
+ }
+
+ /**
+ * Removes a menu item from the menu.
+ *
+ * @param index the index of the menu item to remove
+ */
+ public void delItem(int index)
+ {
+ menu.remove(index);
+ }
+
+ /**
+ * Disables the menu.
+ */
+ public void disable()
+ {
+ menu.setEnabled(false);
+ }
+
+ /**
+ * Enables the menu.
+ */
+ public void enable()
+ {
+ menu.setEnabled(true);
+ }
+
+ /**
+ * Sets the enabled state of the menu to <code>enabled</code>.
+ *
+ * @param enabled if the menu should be enabled or not
+ */
+ public void setEnabled(boolean enabled)
+ {
+ menu.setEnabled(enabled);
+ }
+
+ /**
+ * Sets the label of the menu.
+ *
+ * @param text the label to set
+ */
+ public void setLabel(String text)
+ {
+ menu.setText(text);
+ }
+
+ /**
+ * Releases any reference to the AWT and Swing menu instances.
+ */
+ public void dispose()
+ {
+ menu = null;
+ awtMenu = null;
+ }
+
+ /**
+ * Sets the font for the menu.
+ *
+ * @param font the font to set
+ */
+ public void setFont(Font font)
+ {
+ menu.setFont(font);
+ }
+
+ /**
+ * Handles mouse events by forwarding them to the Swing menu.
+ *
+ * @param ev the mouse event
+ */
+ public void handleMouseEvent(MouseEvent ev)
+ {
+ menu.handleMouseEvent(ev);
+ }
+
+ /**
+ * Handles mouse motion events by forwarding them to the Swing menu.
+ *
+ * @param ev the mouse event
+ */
+ public void handleMouseMotionEvent(MouseEvent ev)
+ {
+ menu.handleMouseMotionEvent(ev);
+ }
+
+ /**
+ * Returns the X coordinate of the upper left corner of the menu. This is
+ * used internally by the SwingMenuBarPeer.
+ *
+ * @return the X coordinate of the upper left corner of the menu
+ */
+ int getX()
+ {
+ return menu.getX();
+ }
+
+ /**
+ * Returns the width of the menu. This is used internally by the
+ * SwingMenuBarPeer.
+ *
+ * @return the X coordinate of the upper left corner of the menu
+ */
+ int getWidth()
+ {
+ return menu.getWidth();
+ }
+
+ /**
+ * Returns the Y coordinate of the upper left corner of the menu. This is
+ * used internally by the SwingMenuBarPeer.
+ *
+ * @return the X coordinate of the upper left corner of the menu
+ */
+ public int getY()
+ {
+ return menu.getY();
+ }
+}
diff --git a/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 <code>SwingPanelPeer</code> 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 <code>this</code>
+ */
+ public JComponent getJComponent()
+ {
+ return this;
+ }
+
+ /**
+ * Handles mouse events by forwarding it to
+ * <code>processMouseEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleMouseEvent(MouseEvent ev)
+ {
+ 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
+ * <code>processMouseMotionEvent()</code>.
+ *
+ * @param ev the mouse motion event
+ */
+ public void handleMouseMotionEvent(MouseEvent ev)
+ {
+ textArea.processMouseMotionEvent(ev);
+ }
+
+ /**
+ * Handles key events by forwarding it to <code>processKeyEvent()</code>.
+ *
+ * @param ev the mouse event
+ */
+ public void handleKeyEvent(KeyEvent ev)
+ {
+ textArea.processKeyEvent(ev);
+ }
+
+ /**
+ * Handles focus events by forwarding it to
+ * <code>processFocusEvent()</code>.
+ *
+ * @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 <code>true</code> if the button is currently showing,
+ * <code>false</code> 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 <code>true</code> if the button is currently showing,
+ * <code>false</code> 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 <code>this</code>
+ */
+ public JComponent getJComponent()
+ {
+ return this;
+ }
+
+ /**
+ * Handles mouse events by forwarding it to the swing textfield.
+ *
+ * @param ev the mouse event
+ */
+ public void handleMouseEvent(MouseEvent ev)
+ {
+ ev.setSource(this);
+ processMouseEvent(ev);
+ }
+
+ /**
+ * Handles mouse motion events by forwarding it to the swing textfield.
+ *
+ * @param ev the mouse motion event
+ */
+ public void handleMouseMotionEvent(MouseEvent ev)
+ {
+ ev.setSource(this);
+ processMouseMotionEvent(ev);
+ }
+
+ /**
+ * Handles key events by forwarding it to the swing textfield.
+ *
+ * @param ev the key event
+ */
+ public void handleKeyEvent(KeyEvent ev)
+ {
+ ev.setSource(this);
+ processKeyEvent(ev);
+ }
+
+ /**
+ * Handles focus events by forwarding it to
+ * <code>processFocusEvent()</code>.
+ *
+ * @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 <code>SwingTextFieldPeer</code> 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 <code>true</code> to make the textfield editable,
+ * <code>false</code> to make it uneditable
+ */
+ public void setEditable(boolean editable)
+ {
+ ((JTextField) swingComponent.getJComponent()).setEditable(editable);
+ }
+
+ /**
+ * Returns the current caret position.
+ *
+ * @return the current caret position
+ */
+ public int getCaretPosition()
+ {
+ return ((JTextField) swingComponent.getJComponent()).getCaret().getDot();
+ }
+
+ /**
+ * Sets the current caret position.
+ *
+ * @param pos the caret position to set
+ */
+ public void setCaretPosition(int pos)
+ {
+ ((JTextField) swingComponent.getJComponent()).getCaret().setDot(pos);
+ }
+
+ /**
+ * Returns the index of the character at the specified location.
+ *
+ * @param x the X coordinate of the point to query
+ * @param y the Y coordinate of the point to query
+ *
+ * @return the index of the character at the specified location
+ */
+ public int getIndexAtPoint(int x, int y)
+ {
+ // TODO: Must be implemented.
+ return 0;
+ }
+
+ /**
+ * Returns the bounds of the character at the specified index.
+ *
+ * @param pos the index of the character
+ *
+ * @return the bounds of the character at the specified index
+ */
+ public Rectangle getCharacterBounds(int pos)
+ {
+ // TODO: Must be implemented.
+ return null;
+ }
+
+ /**
+ * Not used.
+ */
+ public long filterEvents(long filter)
+ {
+ // TODO: Must be implemented.
+ return 0;
+ }
+
+ /**
+ * Not used.
+ */
+ public InputMethodRequests getInputMethodRequests()
+ {
+ // TODO: Must be implemented.
+ return null;
+ }
+
+}
diff --git a/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:
+ * <ul>
+ * <li>{@link ComponentPeer#getLocationOnScreen()}</li>
+ * <li>{@link ComponentPeer#getGraphics()}</li>
+ * <li>{@link ComponentPeer#createImage(int, int)}</li>
+ * </ul>
+ *
+ * @author Roman Kennke (kennke@aicas.com)
+ */
+public abstract class SwingWindowPeer
+ extends SwingContainerPeer
+ implements WindowPeer
+{
+
+ /**
+ * Creates a new instance of WindowPeer.
+ *
+ * @param window the AWT window
+ */
+ public SwingWindowPeer(Window window)
+ {
+ super(window);
+ 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.awt.peer.swing package.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+ <head>
+ <title>Swing based AWT peers</title>
+ </head>
+ <body>
+ <h1>Swing based AWT peers.</h1>
+ <p>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.
+ </p>
+ <p>An actual implementation would have to provide the following:
+ <ul>
+ <li>A concrete implementation of {@link java.awt.Toolkit}, possibly based
+ on {@link SwingToolkit}. This implementation must provide all the missing
+ methods of the <code>SwingToolkit</code>.</li>
+ <li>Concrete implementations of {@link java.awt.peer.DialogPeer},
+ {@link java.awt.peer.FramePeer} and {@link java.awt.peer.WindowPeer},
+ ideally based on their <code>SwingXXXPeer</code> counterparts.
+ Some methods must be specially
+ overridden in those peers to provide useful functionality, like
+ <code>getLocationOnScreen()</code>. See the API documentation for more
+ details</li>
+ <li>An implementation of {@link java.awt.Image}. These must be provided by
+ the toplevel component peers.</li>
+ <li>An implementation of {@link java.awt.Graphics}. This must also be
+ provided by the toplevel peers.</li>
+ <li>An implementation of {@link java.awt.Font}. This must be
+ provided by the toolkit.</li>
+ </ul>
+ </p>
+ </body>
+</html>
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
+ * <code>0</code>.
+ */
+ 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 <code>c</code>.
+ *
+ * @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<Image,ZPixmap> imageCache = new WeakHashMap<Image,ZPixmap>();
+
+ 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<ImageConsumer> consumers = new Vector<ImageConsumer>();
+
+ 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<String,ClasspathFontPeer> fontCache =
+ new WeakHashMap<String,ClasspathFontPeer>();
+
+ 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 <code>PrinterJob</code>.
+ */
+ 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 <code>true</code> if this job has been cancelled, <code>false</code>
+ * otherwise.
+ */
+ public boolean isCancelled()
+ {
+ return cancelled;
+ }
+
+ /**
+ * Clones the specified <code>PageFormat</code> object then alters the
+ * clone so that it represents the default page format.
+ *
+ * @param page_format The <code>PageFormat</code> 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 <code>PageFormat</code> object to modify.
+ *
+ * @return The modified <code>PageFormat</code>.
+ */
+ 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 <code>false</code> if the user cancels the dialog box,
+ * <code>true</code> 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 <code>false</code> if the user cancels the dialog box,
+ * <code>true</code> 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 <code>null</code>.
+ */
+ public void setPageable(Pageable pageable)
+ {
+ if( pageable == null )
+ throw new NullPointerException("Pageable cannot be null.");
+ this.pageable = pageable;
+ }
+
+ /**
+ * Sets this specified <code>Printable</code> as the one to use for
+ * rendering the pages on the print device.
+ *
+ * @param printable The <code>Printable</code> for the print job.
+ */
+ public void setPrintable(Printable printable)
+ {
+ this.printable = printable;
+ }
+
+ /**
+ * Sets the <code>Printable</code> and the page format for the pages
+ * to be printed.
+ *
+ * @param printable The <code>Printable</code> for the print job.
+ * @param page_format The <code>PageFormat</code> 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 <code>PageFormat</code>
+ * 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 <code>PageFormat</code> to validate.
+ *
+ * @return The validated <code>PageFormat</code>.
+ */
+ 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.<P>
+ **
+ ** 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;i<methods.size();i++) {
+ Method thisMethod = ((MethodDescriptor)methods.elementAt(i)).getMethod();
+ if(m.getMethod().getName().equals(thisMethod.getName())
+ && Arrays.equals(m.getMethod().getParameterTypes(),
+ thisMethod.getParameterTypes())) {
+ return true;
+ }
+ }
+ return false;
+ }
+ public void addMethod(MethodDescriptor m) {
+ methods.addElement(m);
+ }
+
+ public void setDefaultPropertyName(String defaultPropertyName) {
+ this.defaultPropertyName = defaultPropertyName;
+ }
+
+ public void setDefaultEventName(String defaultEventName) {
+ this.defaultEventName = defaultEventName;
+ }
+
+ public void setIcons(java.awt.Image[] im) {
+ this.im = im;
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/DefaultExceptionListener.java b/libjava/classpath/gnu/java/beans/DefaultExceptionListener.java
new file mode 100644
index 000000000..124ad9c94
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/DefaultExceptionListener.java
@@ -0,0 +1,66 @@
+/* gnu.java.beans.DefaultExceptionListener
+ Copyright (C) 2004, 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.java.beans;
+
+import java.beans.ExceptionListener;
+
+/** The DefaultExceptionListener is the default implementation of the
+ * {@link ExceptionListener} interface. An instance of
+ * this class is used whenever the user provided no
+ * <code>ExceptionListener</code> instance on its own.
+ *
+ * <p>The implementation just writes the exception's message
+ * to <code>System.err</code> and is used by the {@link java.beans.Encoder}
+ * and the {@link java.beans.XMLDecoder}.
+ * </p>
+ *
+ * @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 <code>AppletContext</code> implementation that does nothing.
+ *
+ * <p>This is the default implementation for GNU Classpath and is used for <code>Applet</code>
+ * beans being created with {@link java.beans.Beans.instantiate}.</p>
+ *
+ * <p>It has no functionality in order to allow it to be used without any dependencies
+ * (e.g. sound, network access, ...).</p>
+ *
+ * @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-<code>null</code> object on
+ * <code>URL.openConnection()</code>.
+ *
+ * @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 <code>Image</code> 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 <code>null</code> for every argument.
+ *
+ * @see java.applet.AppletContext#getApplet(java.lang.String)
+ */
+ public Applet getApplet(String name)
+ {
+ return null;
+ }
+
+ /** Returns always an empty <code>Enumeration</code>.
+ *
+ * @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 <code>null</code> 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 <code>AppletStub</code> providing no functionality.
+ * <p>This class is used for <code>Applet</code> being created with
+ * {@link java.beans.Bean.instantiate}.</p>
+ *
+ * @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 <code>true</code>.
+ *
+ * @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 <code>null</code> 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.<br/>
+ **
+ ** 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:
+ * <ul>
+ * <li>boolean "is" getter</li>
+ * <li>"get" style getter</li>
+ * <li>single argument setter</li>
+ * <li>indiced setter and getter</li>
+ * </ul>
+ * It files the method as a listener method if all of these rules apply:
+ * <ul>
+ * <li>the method name starts with "add" or "remove"</li>
+ * <li>there is only a single argument</li>
+ * <li>the argument type is a subclass of <code>java.util.EventListener</code></li>
+ * </ul>
+ * 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;i<m.length;i++) {
+ addMethod(m[i]);
+ }
+ }
+
+ public void setPropertyStopClass(Class c) {
+ propertyStopClass = c;
+ }
+
+ public void setEventStopClass(Class c) {
+ eventStopClass = c;
+ }
+
+ public void setMethodStopClass(Class c) {
+ methodStopClass = c;
+ }
+
+
+ public BeanInfoEmbryo getBeanInfoEmbryo() throws IntrospectionException {
+ BeanInfoEmbryo b = new BeanInfoEmbryo();
+ findXXX(b,IS);
+ findXXXInt(b,GET_I);
+ findXXXInt(b,SET_I);
+ findXXX(b,GET);
+ findXXX(b,SET);
+ findAddRemovePairs(b);
+ for(int i=0;i<otherMethods.size();i++) {
+ MethodDescriptor newMethod = new MethodDescriptor((Method)otherMethods.elementAt(i));
+ if(!b.hasMethod(newMethod)) {
+ b.addMethod(new MethodDescriptor((Method)otherMethods.elementAt(i)));
+ }
+ }
+ return b;
+ }
+
+ public BeanInfo getBeanInfo() throws IntrospectionException {
+ return getBeanInfoEmbryo().getBeanInfo();
+ }
+
+
+ void findAddRemovePairs(BeanInfoEmbryo b) throws IntrospectionException {
+ Enumeration listenerEnum = listenerMethods.keys();
+ while(listenerEnum.hasMoreElements()) {
+ DoubleKey k = (DoubleKey)listenerEnum.nextElement();
+ Method[] m = (Method[])listenerMethods.get(k);
+ if(m[ADD] != null && m[REMOVE] != null) {
+ EventSetDescriptor e = new EventSetDescriptor(Introspector.decapitalize(k.getName()),
+ k.getType(), k.getType().getMethods(),
+ m[ADD],m[REMOVE]);
+ e.setUnicast(ArrayHelper.contains(m[ADD].getExceptionTypes(),java.util.TooManyListenersException.class));
+ if(!b.hasEvent(e)) {
+ b.addEvent(e);
+ }
+ }
+ }
+ }
+
+ void findXXX(BeanInfoEmbryo b, int funcType) throws IntrospectionException {
+ Enumeration keys = propertyMethods.keys();
+ while(keys.hasMoreElements()) {
+ DoubleKey k = (DoubleKey)keys.nextElement();
+ Method[] m = (Method[])propertyMethods.get(k);
+ if(m[funcType] != null) {
+ PropertyDescriptor p = new PropertyDescriptor(Introspector.decapitalize(k.getName()),
+ m[IS] != null ? m[IS] : m[GET],
+ m[SET]);
+ if(m[SET] != null) {
+ p.setConstrained(ArrayHelper.contains(m[SET].getExceptionTypes(),java.beans.PropertyVetoException.class));
+ }
+ if(!b.hasProperty(p)) {
+ b.addProperty(p);
+ }
+ }
+ }
+ }
+
+ void findXXXInt(BeanInfoEmbryo b, int funcType) throws IntrospectionException {
+ Enumeration keys = propertyMethods.keys();
+ while(keys.hasMoreElements()) {
+ DoubleKey k = (DoubleKey)keys.nextElement();
+ Method[] m = (Method[])propertyMethods.get(k);
+ if(m[funcType] != null) {
+ boolean constrained;
+ if(m[SET_I] != null) {
+ constrained = ArrayHelper.contains(m[SET_I].getExceptionTypes(),java.beans.PropertyVetoException.class);
+ } else {
+ constrained = false;
+ }
+
+ /** Find out if there is an array type get or set **/
+ Class arrayType = Array.newInstance(k.getType(),0).getClass();
+ DoubleKey findSetArray = new DoubleKey(arrayType,k.getName());
+ Method[] m2 = (Method[])propertyMethods.get(findSetArray);
+ IndexedPropertyDescriptor p;
+ if(m2 == null) {
+ p = new IndexedPropertyDescriptor(Introspector.decapitalize(k.getName()),
+ null,null,
+ m[GET_I],m[SET_I]);
+ } else {
+ if(constrained && m2[SET] != null) {
+ constrained = ArrayHelper.contains(m2[SET].getExceptionTypes(),java.beans.PropertyVetoException.class);
+ }
+ p = new IndexedPropertyDescriptor(Introspector.decapitalize(k.getName()),
+ m2[GET],m2[SET],
+ m[GET_I],m[SET_I]);
+ }
+ p.setConstrained(constrained);
+ if(!b.hasProperty(p)) {
+ b.addProperty(p);
+ }
+ }
+ }
+ }
+
+ static final int IS=0;
+ static final int GET_I=1;
+ static final int SET_I=2;
+ static final int GET=3;
+ static final int SET=4;
+
+ static final int ADD=0;
+ static final int REMOVE=1;
+
+ void addToPropertyHash(String name, Method method, int funcType) {
+ String newName;
+ Class type;
+
+ switch(funcType) {
+ case IS:
+ type = java.lang.Boolean.TYPE;
+ newName = name.substring(2);
+ break;
+ case GET_I:
+ type = method.getReturnType();
+ newName = name.substring(3);
+ break;
+ case SET_I:
+ type = method.getParameterTypes()[1];
+ newName = name.substring(3);
+ break;
+ case GET:
+ type = method.getReturnType();
+ newName = name.substring(3);
+ break;
+ case SET:
+ type = method.getParameterTypes()[0];
+ newName = name.substring(3);
+ break;
+ default:
+ return;
+ }
+ newName = capitalize(newName);
+ if (newName.length() == 0)
+ return;
+
+ DoubleKey k = new DoubleKey(type,newName);
+ Method[] methods = (Method[])propertyMethods.get(k);
+ if(methods == null) {
+ methods = new Method[5];
+ propertyMethods.put(k,methods);
+ }
+ methods[funcType] = method;
+ }
+
+ void addToListenerHash(String name, Method method, int funcType) {
+ String newName;
+ Class type;
+
+ switch(funcType) {
+ case ADD:
+ type = method.getParameterTypes()[0];
+ newName = name.substring(3,name.length()-8);
+ break;
+ case REMOVE:
+ type = method.getParameterTypes()[0];
+ newName = name.substring(6,name.length()-8);
+ break;
+ default:
+ return;
+ }
+ newName = capitalize(newName);
+ if (newName.length() == 0)
+ return;
+
+ DoubleKey k = new DoubleKey(type,newName);
+ Method[] methods = (Method[])listenerMethods.get(k);
+ if(methods == null) {
+ methods = new Method[2];
+ listenerMethods.put(k,methods);
+ }
+ methods[funcType] = method;
+ }
+
+ /* Determines whether <code>stopClass</code> is <code>null</code>
+ * or <code>declaringClass<code> is a true subclass of <code>stopClass</code>.
+ * 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 <code>null</code> is the argument, <code>null</code> 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 <code>Class</code> and a
+ * <code>String</code> 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:
+ * <a href="http://java.sun.com/products/jfc/tsc/articles/persistence3/">Java Persistence Article</a>
+ */
+ 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.
+ *
+ * <p>This class provides the implementation for an indexed get and set method.
+ * But this does not mean that the result object supports these operation.</p>
+ *
+ * @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 &lt;array&gt; 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 <array> 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).
+ *
+ * <p>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.</p>
+ *
+ * @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 &lt;boolean&gt; 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 &lt;byte&gt; 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 &lt;char&gt; 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 &lt;class&gt; 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.
+ *
+ * <p>The constructor is invoked when a sub-context is a statement or the Context ends.</p>
+ *
+ * @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.
+ * <p>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.</p>
+ *
+ * @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 &lt;java&gt; 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 &lt;double&gt; 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.
+ *
+ * <p>When the implementation is correct none of this class' methods
+ * (except <code>notifyStatement()</code>) is called.</p>
+ *
+ * @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: <a href="http://java.sun.com/products/jfc/tsc/articles/persistence3">Java Persistence Article</a>.
+ *
+ * @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 &lt;float&gt; 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.
+ *
+ * <p>An IndexContent is a get operation when no argument is provided and a set operation if one
+ * argument is provided.</p>
+ *
+ * @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 &lt;int&gt; 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 &lt;long&gt; 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.
+ *
+ * <p>When the result object is available methods can be called on it using sub-Contexts.</p>
+ *
+ * @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 <void> 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. &lt;int&gt; tag)
+ *
+ * <p>The ObjectContext does not accept any parameter object and ignores notifications
+ * about sub-contexts being statements.</p>
+ *
+ * @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 &lt;object&gt; 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: <object idref="foo" method="bar"/> 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:
+ * <object idref="foo">
+ * <object method="bar"/>
+ * </object>
+ *
+ * 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 <void index="4"/> will make up a get()-call. But this is wrong because
+ // <void/> 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 <object> tag implies that a return
+ // value is expected.
+ return new PropertyContext(id, propertyName);
+ }
+
+ throw new AssemblyException(new IllegalArgumentException("Wrong or missing attributes for <object> 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 <java> 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.
+ * <p>When the method call has to be made and there is no argument we 'get' the property.
+ * With one argument it is 'set'.</p>
+ *
+ * @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 &lt;short&gt; 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.
+ * <p>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.</p>
+ *
+ * @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 <void> 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: <void> tags are not allowed to have an idref attribute
+ throw new AssemblyException(
+ new IllegalArgumentException(
+ (attributes.getValue("idref") == null)
+ ? "Missing attributes for <void> tag"
+ : "<void> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.beans.decoder package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.beans.decoder</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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;i<stdColorNames.length;i++) {
+ if(stdColorNames[i].equalsIgnoreCase(val)) {
+ setValue(stdColors[i]);
+ return;
+ }
+ }
+ if(val.charAt(0) == '#') {
+ setValue(new Color(Integer.parseInt(val.substring(1),16)));
+ } else {
+ setValue(new Color(Integer.parseInt(val,16)));
+ }
+ }
+
+ /** getAsText for Color turns the color into either one of the standard
+ ** colors or into an RGB hex value with # prepended. **/
+ public String getAsText() {
+ for(int i=0;i<stdColors.length;i++) {
+ if(stdColors[i].equals(getValue())) {
+ return stdColorNames[i];
+ }
+ }
+ return "#" + Integer.toHexString(((Color)getValue()).getRGB() & 0x00FFFFFF);
+ }
+
+ /** getTags for Color returns a list of standard colors. **/
+ public String[] getTags() {
+ return stdColorNames;
+ }
+}
diff --git a/libjava/classpath/gnu/java/beans/editors/FontEditor.java b/libjava/classpath/gnu/java/beans/editors/FontEditor.java
new file mode 100644
index 000000000..dfccb4ede
--- /dev/null
+++ b/libjava/classpath/gnu/java/beans/editors/FontEditor.java
@@ -0,0 +1,77 @@
+/* gnu.java.beans.editors.FontEditor
+ 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.Font;
+import java.beans.PropertyEditorSupport;
+
+/**
+ ** FontEditor is a property editor for java.awt.Font.
+ **
+ ** <STRONG>To Do:</STRONG> 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.<P>
+ **
+ ** <STRONG>To Do:</STRONG> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.beans.editors package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.beans.editors</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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;
+
+/** <p>The <code>ClassPersistenceDelegate</code> creates
+ * <code>Expression</code> instances which denote class resolutions.</p>
+ *
+ * <p>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 <code>Class.forName</code>. However for the <code>Class</code> class
+ * we call <code>getClass()</code> on a <code>String.class</code> instance.
+ * This in turn lead to the resolution of the String class which is always
+ * encoded as <code>"".getClass()</code>. Finally the <code>Encoder</code>
+ * 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;
+
+/** <p>A <code>PersistenceDelegate</code> 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.</p>
+ *
+ * <p>It is used for <code>Set</code> and <code>List</code>
+ * implementations.</p>
+ *
+ * @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 <code>Contect</code> object describes the current state
+ * and the call number while processing the original object
+ * tree in the {@link ScanEngine}.
+ *
+ * <p>The class allows to distinguish the different calling states
+ * and is neccessary for the child element skipping feature of
+ * the {@link GenericScannerState}.</p>
+ *
+ * @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.
+ *
+ * <p>Furthermore it can optionally skip a certain number of child
+ * elements. The algorithm can cope with the fact that one
+ * <code>GenericScannerState</code> instance may be called at
+ * different levels of recursions.</p>
+ *
+ * @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.
+ *
+ * <p>Consider the call hierarchy:
+ * <code>
+ * methodInvocation
+ * objectInstantiation
+ * classResolution*
+ * objectInstantiation
+ * classResolution
+ * </code>
+ * </p>
+ *
+ * <p>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 <code>IgnoringScannerState</code>.</p>
+ *
+ * <p>Setting the default successor of a <code>IgnoringScannerState</code>
+ * to itself causes all elements of the call hierarchy to be skipped
+ * until another state is reached by going back.</p>
+ *
+ * @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;
+
+/**
+ * <p>
+ * ObjectId provides an object identification mechanism which gives each object
+ * a name in the form <code>&lt;class&gt;&lt;Nameindex&gt;</code>.
+ * </p>
+ *
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * An <code>ObjectId</code> 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.
+ * </p>
+ *
+ * @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 : "<unused id>";
+ }
+
+ /**
+ * <p>
+ * Generates a simple Id by concatenating a class name with a self-increasing
+ * number.
+ * </p>
+ */
+ 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 <code>ScannerState</code> 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;
+
+/** <p><code>Root</code> provides a simple interface to a tree of
+ * objects.</p>
+ *
+ * <p>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 <code>Root</code> and
+ * {@link gnu.java.beans.encoder.elements.Element} class can provide
+ * context information which is used to write the best fitting
+ * XML representation.</p>
+ *
+ * @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();
+ }
+
+ /** <p>Adds another child element to the tree.</p>
+ *
+ * <p>The new element automatically becomes the current
+ * element.</p>
+ *
+ * @param elem The new child element.
+ */
+ public void addChild(Element elem)
+ {
+ current.addChild(elem);
+
+ parents.push(current);
+ current = elem;
+ }
+
+ /**
+ * <p>Marks that the end of the current element
+ * is reached and that no more childs are added to
+ * it.</p>
+ *
+ * <p>The behavior is to return to the nearest parent
+ * element.</p>
+ */
+ public void end()
+ {
+ current = (Element) parents.pop();
+ }
+
+ /**
+ * <p>Goes back to the nearest parent element but
+ * deletes the just created child.</p>
+ *
+ * <p>This is used if something went wrong while
+ * processing the child element's {@link java.beans.Expression}
+ * or {@link java.beans.Statement}.</p>
+ *
+ */
+ public void deleteLast()
+ {
+ current = (Element) parents.pop();
+
+ current.removeLast();
+ }
+
+ /**
+ * <p>Traverses the elements in the object tree
+ * and creates their XML representation in the output
+ * stream of the given {@link Writer}.</p>
+ *
+ * <p>Finally the <code>Writer</code> is flushed.</p>
+ *
+ * @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();
+ }
+ }
+
+ /** <p>A special Element implementation that represents the
+ * encoder's context.</p>
+ *
+ * <p>This element is written only once per Writer.</p>
+ *
+ * <p>It is assumed that this element is never empty to simplify
+ * the implementation.</p>
+ *
+ * @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;
+
+/** <p>The <code>ScanEngine</code> 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.</p>
+ *
+ * <p>How does it work?</p>
+ * <p>The <code>ScanEngine</code> sits below the {@link java.beans.XMLEncoder}
+ * class and is called by it exclusively. The <code>XMLEncoder</code> sends
+ * interpretive data by invoking {@link #writeExpression}, {@link #writeStatement}
+ * and {@link #writeObject}. The invocations of <code>writeExpression</code> and
+ * <code>writeStatement</code> are usually nested into each other and provide
+ * more information then necessary to generate the XML representation.
+ * Furthermore the meaning of certain <code>Expressions</code> differs
+ * depending on the enclosing elements or the inner elements have to be
+ * simply discarded.</p>
+ *
+ * <p>To cope with this state dependant nature the <code>ScanEngine</code>
+ * contains a state machine which is programmed statically (no adjustments are
+ * needed, all <code>ScanEngine</code> engines use the same setup). The
+ * <code>ScanEngine</code>'s job is to decode the <code>Expression</code>s,
+ * <code>Statement</code>s and certain objects (namely <code>String</code>,
+ * <code>null</code> 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 <code>Expression</code> 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 <code>ScanEngine</code> 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.</p>
+ *
+ * <p>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 <code>writeStatement</code>, <code>writeExpression</code>
+ * in the <code>XMLEncoder</code> ends by calling the {@link #end} method.
+ * Note that due to the inheritance relationship of <code>Encoder</code>
+ * and <code>XMLEncoder</code> it is impossible for the
+ * <code>ScanEngine</code> 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.</p>
+ *
+ * <p>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 <code>ObjectId</code>
+ * instance is stored in the <code>ScanEngine</code> and gets cleared whenever
+ * the {@link #flush} method is called. This method also writes the currently
+ * built object tree and generates the XML representation.</p>
+ *
+ * @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 <code>ScannerState</code> under a certain name.
+ *
+ * @param name Name of the state
+ * @param state The <code>ScannerState</code> 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.
+ *
+ * <p>Objects are unsuitable if they are an instance of a primitive wrapper
+ * or String.</p>
+ *
+ * @param value The object to retrieve an id for.
+ * @return The id for the object or <code>null</code>.
+ */
+ 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 <void> 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.
+ *
+ * <p>This involves saving the current state, retrieving it's
+ * successor and setting it as the current state.</p>
+ *
+ * @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.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @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.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @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.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @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.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @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.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @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.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @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.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @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.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @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.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @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.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ *
+ * @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.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ */
+ void listSet()
+ {
+ transition(ScannerState.TRANSITION_LIST_SET);
+
+ current.listSet();
+ }
+
+ /** Event method that denotes the retrieval of a value in a list.
+ *
+ * <p>More details about this method can be found in this
+ * class' introduction.</p>
+ */
+ 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;
+
+/** <p>Provides the infrastructure for the state machine and the transition
+ * mechanism.</p>
+ *
+ * <p>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.</p>
+ *
+ * @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;
+ }
+
+ /**
+ * <p>Stores a successor's state name for a certain transition.</p>
+ *
+ * <p>This method is only used at the configuration time of the state
+ * machine.</p>
+ *
+ * @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);
+ }
+
+ /** <p>Retrieves a the state name of a successor for the given transition
+ * constant.</p>
+ *
+ * <p>Returns the default successor's state name if no special setup was
+ * prepared.</p>
+ *
+ * @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);
+
+ /**
+ * <p>A special event that does not provoke a direct transition.</p>
+ *
+ * <p>Instead the transition is done by the <code>ScanEngine</code>: It goes
+ * back to the previous state and just uses this method to inform the state
+ * about this happening.</p>
+ */
+ 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 <code>Writer</code> represents a simplified interface to an XML
+ * writer that is used for the XML persistence mechanism.
+ *
+ * <p>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.</p>
+ *
+ * <p>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.</p>
+ *
+ * <p>The <code>Writer</code> 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.</p>
+ *
+ * <p>Write
+ * <code>
+ * &lt;element/&gt;
+ * </code>
+ * by issuing <code>write("element", true)</code> (or any of the other
+ * write-variants that allows specifying the <code>isEmpty</code> argument)
+ * and <code>writeEnd(true)</code>.</p>
+ *
+ * <p>Write
+ * <code>
+ * &lt;element&gt;body&lt;/element&gt;
+ * </code>
+ * by issuing <code>writeNoChildren("element", "body")</code> and <code>writeNoChildrenEnd()</code>.</p>
+ *
+ * <p>
+ * Write
+ * <code>
+ * &lt;element&gt;
+ * &lt;child1/&gt;
+ * &lt;child2/&gt;
+ * ...
+ * &lt;element/&gt;
+ * </code>
+ * by issuing <code>write("element", false)</code> (or any of the other
+ * write-variants that allows specifying the <code>isEmpty</code> argument)
+ * and <code>writeEnd(false)</code>.</p>
+ *
+ * <p>Note: It is important that the values of <code>isEmpty</code> and
+ * <code>wasEmpty</code> match. Otherwise strange things might happen to
+ * the layout.</p>
+ *
+ * @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.
+ *
+ * <p>If your tag has not generated any body text or child
+ * elements provide <code>true</code> 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.
+ *
+ * <p>Must be used in combination with {@link writeNoChildren} only.</p>
+ */
+ 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;
+
+/** <code>Element</code> is the base class for the object tree elements.
+ *
+ * <p>It provides the neccessary infrastructure every element subclass
+ * needs in order to interact with the {@link gnu.java.beans.encoder.Root}
+ * class.</p>
+ *
+ * @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
+ * <code>Element</code>.
+ *
+ * <p>This can only be done once.</p>
+ *
+ * @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 <code>Element</code>.
+ *
+ * @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.
+ *
+ * <p>This method is useful to decide which formatting variant
+ * for the XML element can be chosen.</p>
+ *
+ * @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 <code>null</code>.
+ */
+ 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.
+ *
+ * <p>By default this does <code>writer.writeEnd(children.isEmpty())</code>.
+ * Override if neccessary, for example when using the
+ * {@link gnu.java.beans.encoder.Writer#writeNoChildren}</code> 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 <code>null</code> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.beans package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.beans</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 <code>ObjectIdentityMap2Int</code>.
+ */
+ 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 <code>Object</code> that makes
+ the methods <code>hashCode()</code> and <code>equals(Object)</code>
+ as discriminating as possible.
+*/
+public class ObjectIdentityWrapper
+{
+
+ /**
+ Constructs a <code>ObjectIdentityWrapper</code> that is wrapped
+ around o.
+ */
+ public ObjectIdentityWrapper( Object o )
+ {
+ object = o;
+ }
+
+ /**
+ Uses <code>System.identityHashCode(Object)</code> to compute a
+ hash code for the object wrapped by this
+ <code>ObjectIdentityWrapper</code>.
+
+ @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 <code>==</code> operator to test for equality between
+ the object wrapped by this <code>ObjectIdentityWrapper</code> and
+ the object wrapped by the <code>ObjectIdentityWrapper</code> o.
+ Returns false if o is not a <code>ObjectIdentityWrapper</code>.
+
+ @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 <code>Object</code> wrapped by this
+ <code>ObjectIdentityWrapper</code>.
+ */
+ 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.io package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.io</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 <code>equals(searchFor)</code>
+ */
+ 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 <code>CPStringBuilder</code> 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 <code>CPStringBuilder</code> with the characters in the
+ * specified <code>String</code>. Initial capacity will be the size of the
+ * String plus the default capacity.
+ *
+ * @param str the <code>String</code> 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 <code>CPStringBuilder</code> with the characters in the
+ * specified <code>StringBuffer</code>. Initial capacity will be the size of the
+ * String plus the default capacity.
+ *
+ * @param str the <code>String</code> 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 <code>CPStringBuilder</code> with the characters in the
+ * specified <code>StringBuilder</code>. Initial capacity will be the size of the
+ * String plus the default capacity.
+ *
+ * @param str the <code>String</code> 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 <code>CPStringBuilder</code> with the characters in the
+ * specified <code>CharSequence</code>. 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 <code>CharSequence</code>
+ * @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 <code>newLength</code>
+ * 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 &gt;= 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 &gt;= 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 <code>index-1</code> and
+ * <code>index-2</code> 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 &gt;= 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. <code>srcOffset - srcEnd</code>
+ * 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 &gt;= 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 <code>String</code> value of the argument to this
+ * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
+ * to <code>String</code>.
+ *
+ * @param obj the <code>Object</code> to convert and append
+ * @return this <code>StringBuffer</code>
+ * @see String#valueOf(Object)
+ * @see #append(String)
+ */
+ public CPStringBuilder append(Object obj)
+ {
+ return append(String.valueOf(obj));
+ }
+
+ /**
+ * Append the <code>String</code> to this <code>StringBuffer</code>. If
+ * str is null, the String "null" is appended.
+ *
+ * @param str the <code>String</code> to append
+ * @return this <code>StringBuffer</code>
+ */
+ 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 <code>StringBuilder</code> value of the argument to this
+ * <code>StringBuilder</code>. This behaves the same as
+ * <code>append((Object) stringBuffer)</code>, except it is more efficient.
+ *
+ * @param stringBuffer the <code>StringBuilder</code> to convert and append
+ * @return this <code>StringBuilder</code>
+ * @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 <code>char</code> array to this <code>StringBuffer</code>.
+ * This is similar (but more efficient) than
+ * <code>append(new String(data))</code>, except in the case of null.
+ *
+ * @param data the <code>char[]</code> to append
+ * @return this <code>StringBuffer</code>
+ * @throws NullPointerException if <code>str</code> is <code>null</code>
+ * @see #append(char[], int, int)
+ */
+ public CPStringBuilder append(char[] data)
+ {
+ return append(data, 0, data.length);
+ }
+
+ /**
+ * Append part of the <code>char</code> array to this
+ * <code>StringBuffer</code>. This is similar (but more efficient) than
+ * <code>append(new String(data, offset, count))</code>, except in the case
+ * of null.
+ *
+ * @param data the <code>char[]</code> to append
+ * @param offset the start location in <code>str</code>
+ * @param count the number of characters to get from <code>str</code>
+ * @return this <code>StringBuffer</code>
+ * @throws NullPointerException if <code>str</code> is <code>null</code>
+ * @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 <code>String</code> value of the argument to this
+ * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
+ * to <code>String</code>.
+ *
+ * @param bool the <code>boolean</code> to convert and append
+ * @return this <code>StringBuffer</code>
+ * @see String#valueOf(boolean)
+ */
+ public CPStringBuilder append(boolean bool)
+ {
+ return append(bool ? "true" : "false");
+ }
+
+ /**
+ * Append the <code>char</code> to this <code>StringBuffer</code>.
+ *
+ * @param ch the <code>char</code> to append
+ * @return this <code>StringBuffer</code>
+ */
+ public CPStringBuilder append(char ch)
+ {
+ ensureCapacity(count + 1);
+ value[count++] = ch;
+ return this;
+ }
+
+ /**
+ * Append the characters in the <code>CharSequence</code> to this
+ * buffer.
+ *
+ * @param seq the <code>CharSequence</code> providing the characters
+ * @return this <code>StringBuffer</code>
+ * @since 1.5
+ */
+ public CPStringBuilder append(CharSequence seq)
+ {
+ return append(seq, 0, seq.length());
+ }
+
+ /**
+ * Append some characters from the <code>CharSequence</code> to this
+ * buffer. If the argument is null, the four characters "null" are
+ * appended.
+ *
+ * @param seq the <code>CharSequence</code> providing the characters
+ * @param start the starting index
+ * @param end one past the final index
+ * @return this <code>StringBuffer</code>
+ * @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 <code>String</code> value of the argument to this
+ * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
+ * to <code>String</code>.
+ *
+ * @param inum the <code>int</code> to convert and append
+ * @return this <code>StringBuffer</code>
+ * @see String#valueOf(int)
+ */
+ // This is native in libgcj, for efficiency.
+ public CPStringBuilder append(int inum)
+ {
+ return append(String.valueOf(inum));
+ }
+
+ /**
+ * Append the <code>String</code> value of the argument to this
+ * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
+ * to <code>String</code>.
+ *
+ * @param lnum the <code>long</code> to convert and append
+ * @return this <code>StringBuffer</code>
+ * @see String#valueOf(long)
+ */
+ public CPStringBuilder append(long lnum)
+ {
+ return append(Long.toString(lnum, 10));
+ }
+
+ /**
+ * Append the <code>String</code> value of the argument to this
+ * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
+ * to <code>String</code>.
+ *
+ * @param fnum the <code>float</code> to convert and append
+ * @return this <code>StringBuffer</code>
+ * @see String#valueOf(float)
+ */
+ public CPStringBuilder append(float fnum)
+ {
+ return append(Float.toString(fnum));
+ }
+
+ /**
+ * Append the <code>String</code> value of the argument to this
+ * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
+ * to <code>String</code>.
+ *
+ * @param dnum the <code>double</code> to convert and append
+ * @return this <code>StringBuffer</code>
+ * @see String#valueOf(double)
+ */
+ public CPStringBuilder append(double dnum)
+ {
+ return append(Double.toString(dnum));
+ }
+
+ /**
+ * Append the code point to this <code>StringBuffer</code>.
+ * 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 <code>StringBuffer</code>
+ * @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 <code>StringBuffer</code>.
+ * <code>delete(10, 12)</code> 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 <code>StringBuffer</code>
+ * @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 <code>StringBuffer</code>.
+ *
+ * @param index the index of the character to delete
+ * @return this <code>StringBuffer</code>
+ * @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 <code>start</code> (inclusive) and
+ * <code>end</code> (exclusive) with <code>str</code>. If <code>end</code>
+ * is larger than the size of this StringBuffer, all characters after
+ * <code>start</code> 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 <code>String</code> to insert
+ * @return this <code>StringBuffer</code>
+ * @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 <code>char[]</code> argument into this
+ * <code>StringBuffer</code>.
+ *
+ * @param offset the place to insert in this buffer
+ * @param str the <code>char[]</code> to insert
+ * @param str_offset the index in <code>str</code> to start inserting from
+ * @param len the number of characters to insert
+ * @return this <code>StringBuffer</code>
+ * @throws NullPointerException if <code>str</code> is <code>null</code>
+ * @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 <code>String</code> value of the argument into this
+ * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
+ * to <code>String</code>.
+ *
+ * @param offset the place to insert in this buffer
+ * @param obj the <code>Object</code> to convert and insert
+ * @return this <code>StringBuffer</code>
+ * @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 <code>String</code> argument into this
+ * <code>StringBuffer</code>. If str is null, the String "null" is used
+ * instead.
+ *
+ * @param offset the place to insert in this buffer
+ * @param str the <code>String</code> to insert
+ * @return this <code>StringBuffer</code>
+ * @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 <code>CharSequence</code> argument into this
+ * <code>StringBuffer</code>. If the sequence is null, the String
+ * "null" is used instead.
+ *
+ * @param offset the place to insert in this buffer
+ * @param sequence the <code>CharSequence</code> to insert
+ * @return this <code>StringBuffer</code>
+ * @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 <code>CharSequence</code> argument into this
+ * <code>StringBuffer</code>. If the sequence is null, the String
+ * "null" is used instead.
+ *
+ * @param offset the place to insert in this buffer
+ * @param sequence the <code>CharSequence</code> to insert
+ * @param start the starting index of the subsequence
+ * @param end one past the ending index of the subsequence
+ * @return this <code>StringBuffer</code>
+ * @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 <code>char[]</code> argument into this
+ * <code>StringBuffer</code>.
+ *
+ * @param offset the place to insert in this buffer
+ * @param data the <code>char[]</code> to insert
+ * @return this <code>StringBuffer</code>
+ * @throws NullPointerException if <code>data</code> is <code>null</code>
+ * @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 <code>String</code> value of the argument into this
+ * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
+ * to <code>String</code>.
+ *
+ * @param offset the place to insert in this buffer
+ * @param bool the <code>boolean</code> to convert and insert
+ * @return this <code>StringBuffer</code>
+ * @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 <code>char</code> argument into this <code>StringBuffer</code>.
+ *
+ * @param offset the place to insert in this buffer
+ * @param ch the <code>char</code> to insert
+ * @return this <code>StringBuffer</code>
+ * @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 <code>String</code> value of the argument into this
+ * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
+ * to <code>String</code>.
+ *
+ * @param offset the place to insert in this buffer
+ * @param inum the <code>int</code> to convert and insert
+ * @return this <code>StringBuffer</code>
+ * @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 <code>String</code> value of the argument into this
+ * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
+ * to <code>String</code>.
+ *
+ * @param offset the place to insert in this buffer
+ * @param lnum the <code>long</code> to convert and insert
+ * @return this <code>StringBuffer</code>
+ * @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 <code>String</code> value of the argument into this
+ * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
+ * to <code>String</code>.
+ *
+ * @param offset the place to insert in this buffer
+ * @param fnum the <code>float</code> to convert and insert
+ * @return this <code>StringBuffer</code>
+ * @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 <code>String</code> value of the argument into this
+ * <code>StringBuffer</code>. Uses <code>String.valueOf()</code> to convert
+ * to <code>String</code>.
+ *
+ * @param offset the place to insert in this buffer
+ * @param dnum the <code>double</code> to convert and insert
+ * @return this <code>StringBuffer</code>
+ * @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 <code>StringBuffer</code>
+ */
+ 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
+ * <code>StringBuffer</code>. 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 <code>StringBuilder</code>. This will
+ * ensure that an expensive growing operation will not occur until either
+ * <code>minimumCapacity</code> is reached or the array has been allocated.
+ * The buffer is grown to either <code>minimumCapacity * 2</code>, if
+ * the array has been allocated or the larger of <code>minimumCapacity</code> and
+ * <code>capacity() * 2 + 2</code>, 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 <code>String</code> this <code>StringBuilder</code>
+ * would create. Not to be confused with the <em>capacity</em> of the
+ * <code>StringBuilder</code>.
+ *
+ * @return the length of this <code>StringBuilder</code>
+ * @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 <code>substring(beginIndex, endIndex)</code>, 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 <code>CPStringBuilder</code> to a <code>String</code>. 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
+ * <code>../doc/unicode/UnicodeData-4.0.0.txt</code> and
+ * <code>../doc/unicode/SpecialCasing-4.0.0.txt</code>, by some
+ * perl scripts. These Unicode definition files can be found on the
+ * <a href="http://www.unicode.org">http://www.unicode.org</a> 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 <code>char[]</code> components. The fields
+ * are stored in arrays of 17 elements each, one element per Unicode plane.
+ * <code>BLOCKS</code> stores the offset of a block of 2<sup>SHIFT</sup>
+ * characters within <code>DATA</code>. The DATA field, in turn, stores
+ * information about each character in the low order bits, and an offset
+ * into the attribute tables <code>UPPER</code>, <code>LOWER</code>,
+ * <code>NUM_VALUE</code>, and <code>DIRECTION</code>. 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 <code>TITLE</code> exceptions (most characters
+ * just have the same title case as upper case). Finally, there are two
+ * tables for multi-character capitalization, <code>UPPER_SPECIAL</code>
+ * which lists the characters which are special cased, and
+ * <code>UPPER_EXPAND</code>, 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,
+ * <code>(char) (BLOCKS.value[ch >> SHIFT[p]] + ch)</code> is the index
+ * where <code>ch</code> is described in <code>DATA</code> if <code>ch</code>
+ * is in Unicode plane <code>p</code>. Note that <code>p</code> 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 <code>DATA</code>.
+ * Each entry has been adjusted so that the 16-bit sum with the desired
+ * character gives the actual index into <code>DATA</code>.
+ */
+ 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("
+ + "2<FPZ\u2710\021\022\023\uffff\000"
+ + "\001\002\003\004\005\006\007\010\011\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"
+ + "\004\005\006\007\010\011\uffff\uffff\uffff\001\002"
+ + "\003\004\005\006\007\010\011\012\013\0142"
+ + "d\u01f4\u03e8\001\002\003\004\005\006\007\010"
+ + "\011\012\013\0142d\u01f4\u03e8\u03e8\u1388\u2710"
+ + "\uffff\012\013\014\015\016\017\020\021\022\023"
+ + "\024\uffff\uffff\013\014\015\016\017\020\021\022"
+ + "\023\024\012\000\001\002\003\004\005\006\007"
+ + "\010\011\012\024\036\005\006\007\010\011\025"
+ + "\026\027\030\031\032\033\034\035\036\037 "
+ + "!\"#$%&'()*+"
+ + ",-./012\uffff\uffff\uffff",
+
+ "\uffff\uffff\uffff\uffff\uffff\001\002\003\004\005\006"
+ + "\007\010\011\012\024\036(2<FP"
+ + "Zd\u00c8\u012c\u0190\u01f4\u0258\u02bc\u0320\u0384\u03e8"
+ + "\u07d0\u0bb8\u0fa0\u1388\u1770\u1b58\u1f40\u2328\u2710\u4e20\u7530"
+ + "\ufffd\ufffc\ufffb\ufffa\ufff9\ufff8\uffff\uffff\uffff\000\001"
+ + "\002\003\004\005\006\007\010\011\uffff\uffff\uffff"
+ + "\uffff\uffff\uffff\uffff\uffff\000\001\002\003\004\005"
+ + "\006\007\010\011",
+
+ "\uffff\uffff",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "\uffff\uffff\uffff",
+
+ "",
+
+ ""};
+
+ /**
+ * This is the attribute table for computing the single-character uppercase
+ * representation of a character. The value is the signed difference
+ * between the character and its uppercase version. Note that this is
+ * stored as an unsigned char since this is a String literal. When
+ * capitalizing a String, you must first check if a multi-character uppercase
+ * sequence exists before using this character.
+ */
+ String[] UPPER = new String[]{
+ "\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\uffe0"
+ + "\uffe0\uffe0\uffe0\uffe0\uffe0\uffe0\uffe0\uffe0\uffe0\uffe0\uffe0"
+ + "\uffe0\uffe0\uffe0\uffe0\uffe0\uffe0\uffe0\uffe0\uffe0\uffe0\uffe0"
+ + "\uffe0\uffe0\uffe0\000\000\000\000\000\000\000\000"
+ + "\u02e7\000\000\000\000\000\uffe0y\000\uffff\000"
+ + "\uff18\000\ufed4\000\000\000\000\000\000\000a"
+ + "\000\000\000\u0082\000\000\000\000\0008\000"
+ + "\uffff\ufffe\uffb1\000\000\000\000\uff2e\uff32\uff33\uff36"
+ + "\uff35\uff31\uff2f\uff2d\uff2b\uff2a\uff26\uff27\uff25\000\000"
+ + "\000T\000\000\000\000\000\uffda\uffdb\uffe1\uffc0"
+ + "\uffc1\uffc2\uffc7\000\uffd1\uffca\uffaa\uffb0\007\000\uffa0"
+ + "\000\000\000\000\000\000\uffd0\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\uffc5"
+ + "\010\000JVd\u0080p~\010\000\011"
+ + "\000\000\ue3db\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\ufff0\ufff0\ufff0\ufff0\ufff0\ufff0\ufff0\ufff0"
+ + "\ufff0\ufff0\ufff0\ufff0\ufff0\ufff0\ufff0\ufff0\000\000\000"
+ + "\000\000\000\000\000\000\000\000\000\000\000"
+ + "\000\000\uffe6\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\uffd8\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",
+
+ "",
+
+ ""};
+
+ /**
+ * This is the attribute table for computing the lowercase representation
+ * of a character. The value is the signed difference between the
+ * character and its lowercase version. Note that this is stored as an
+ * unsigned char since this is a String literal.
+ */
+ String[] LOWER = new String[]{
+ "\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\001\000\uff39"
+ + "\000\uff87\000\u00d2\u00ce\u00cdO\u00ca\u00cb\u00cf\000"
+ + "\u00d3\u00d1\u00d5\000\u00d6\u00da\u00d9\u00db\000\000\002"
+ + "\001\000\000\uff9f\uffc8\uff7e\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\uffc4\000"
+ + "\ufff9P\000\0000\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\ufff8\000\000\000\000\000\000\000\ufff8\000"
+ + "\uffb6\ufff7\000\uffaa\uff9c\uff90\uff80\uff82\000\000\000"
+ + "\000\000\000\000\000\000\000\000\000\000\000"
+ + "\000\000\000\000\000\000\ue2a3\udf41\udfba\020\020"
+ + "\020\020\020\020\020\020\020\020\020\020\020"
+ + "\020\020\020\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\032\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"
+ + "\000\000\000\000\000\000\000\000\000\000\000"
+ + "\000\000\000\000",
+
+ "\000\000",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "\000\000\000",
+
+ "",
+
+ ""};
+
+ /**
+ * This is the attribute table for computing the directionality class
+ * of a character, as well as a marker of characters with a multi-character
+ * capitalization. The direction is taken by performing a signed shift
+ * right by 2 (where a result of -1 means an unknown direction, such as
+ * for undefined characters). The lower 2 bits form a count of the
+ * additional characters that will be added to a String when performing
+ * multi-character uppercase expansion. This count is also used, along with
+ * the offset in UPPER_SPECIAL, to determine how much of UPPER_EXPAND to use
+ * when performing the case conversion. Note that this information is stored
+ * as an unsigned char since this is a String literal.
+ */
+ String[] DIRECTION = new String[]{
+ "$,(004\024\02444\024"
+ + "\034\024\020\014\014\014\014\014\014\014\014"
+ + "\014\01444\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\00044\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\0344\00044\024\014\014"
+ + "\000\01444\000\001\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\ufffc\000\000\000\000"
+ + "\000\000\000\000\000\000\000\000\000\0004"
+ + " \000\000\000\000\002\000\000\000\000"
+ + "\000\000\000\000\000\000\000\000\000\000\000"
+ + "\000\000\000 \000\000\0004\004\004\010"
+ + "\010\010\010\030\030\030\030\030\030\030\030"
+ + "\030\030\030\010$\000\000\000\000\000\000"
+ + "\000\000\000\000\000\000\000\000\000\000\000"
+ + "\000\000\000\000\000\00044\000\000\000"
+ + "\000\000\000\000\000\000\000\000\000\0004"
+ + "444444444 \000"
+ + "\000\000\000\000\000\000\000\000\001\001\001"
+ + "\000\001\000\000\000\000\000\0000$\004"
+ + "4440(8@H<D\014"
+ + "\014\014\014\014\014\014\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\014\014\014\014\014\014\014\014\014\014"
+ + "\014\000\00044444444"
+ + "444\000\000\000\000\000\000\000\000"
+ + "\000\000\000\000\000\000\000\000\000\0004"
+ + "44444444444"
+ + "44444444444"
+ + "4444444\000\000\010",
+
+ "\000\ufffc\0004\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\004\000 "
+ + "$4\000\000\000\014\014\014\014\014\014"
+ + "\014\014\014\014",
+
+ "\000\ufffc",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "",
+
+ "\ufffc$ ",
+
+ "",
+
+ ""};
+
+ /**
+ * This is the listing of titlecase special cases (all other characters
+ * can use <code>UPPER</code> 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 <code>premain</code> function
+ * that is called before the <code>main</code> function.
+ *
+ * @author Nicolas Geoffray (nicolas.geoffray@menlina.com)
+ * @since 1.5
+ */
+public final class InstrumentationImpl implements Instrumentation
+{
+
+ /* List of transformers */
+ private ArrayList<ClassFileTransformer> transformers =
+ new ArrayList<ClassFileTransformer>();
+
+
+ InstrumentationImpl()
+ {
+ }
+
+ /**
+ * Adds a <code>ClassFileTransformer</class> object
+ * to the instrumentation. Each time a class is defined
+ * or redefined, the <code>transform</code> method of the
+ * <code>transformer</code> 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<ClassFileTransformer> 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 <code>BeanImpl</code>.
+ *
+ * @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<Object>)
+ 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<Object>)
+ param.getOpenType()),
+ oldA[a].isReadable(),
+ oldA[a].isWritable(),
+ oldA[a].isIs(),
+ param.getDefaultValue(),
+ ((Comparable<Object>)
+ param.getMinValue()),
+ ((Comparable<Object>)
+ 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<Object>)
+ param.getOpenType()),
+ param.getDefaultValue(),
+ lv);
+ }
+ else
+ sig[a] = new OpenMBeanParameterInfoSupport(oldS[a].getName(),
+ oldS[a].getDescription(),
+ ((OpenType<Object>)
+ param.getOpenType()),
+ param.getDefaultValue(),
+ ((Comparable<Object>)
+ param.getMinValue()),
+ ((Comparable<Object>)
+ 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 <code>ClassLoadingMXBeanImpl</code>.
+ *
+ * @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 <code>CompilationMXBeanImpl</code>.
+ *
+ * @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 <code>GarbageCollectorMXBeanImpl</code>.
+ *
+ * @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 <code>MemoryMXBeanImpl</code>.
+ *
+ * @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 <code>MemoryManagerMXBeanImpl</code>.
+ *
+ * @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 <code>MemoryManagerMXBeanImpl</code>
+ * 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 <code>MemoryPoolMXBeanImpl</code>.
+ *
+ * @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 <code>OperatingSystemMXBeanImpl</code>.
+ *
+ * @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 <code>RuntimeMXBeanImpl</code>.
+ *
+ * @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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.lang.management package.
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+<head><title>GNU Classpath - gnu.java.lang.management</title></head>
+
+<body>
+<p>GNU implementations of the Java system management beans.</p>
+
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.lang package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.lang</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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<Type> interfaces = new ArrayList<Type>();
+ 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<TypeVariable> params = new ArrayList<TypeVariable>();
+ 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<Type> bounds = new ArrayList<Type>();
+ 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<Type> list = new ArrayList<Type>();
+ 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<Type> args = new ArrayList<Type>();
+ while (peekChar() != ')')
+ {
+ args.add(readTypeSignature());
+ }
+ argTypes = new Type[args.size()];
+ args.toArray(argTypes);
+ consume(')');
+ retType = readTypeSignature();
+ ArrayList<Type> throwsSigs = new ArrayList<Type>();
+ 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 <code>Class</code>s or <code>Member</code>s.
+ * More specific methods are also provided for computing the
+ * type-signature of <code>Constructor</code>s and
+ * <code>Method</code>s. Methods are also provided to go in the
+ * reverse direction.
+ *
+ * @author Eric Blake (ebb9@email.byu.edu)
+ */
+public class TypeSignature
+{
+ /**
+ * Returns a <code>String</code> 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:
+ *
+ * <pre>
+ * 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 + ";"
+ * </pre>
+ *
+ * @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 <code>getEncodingOfClass</code>. 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 <code>null</code>. 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 <code>getEncodingOfClass</code>. 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
+ * <code>loader</code> 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 <code>String</code> 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 <code>String</code> 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 <code>String</code> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.lang.reflect package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.lang.reflect</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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
+{
+ /**
+ * <p>
+ * 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:
+ * </p>
+ * <ol>
+ * <li>If the variant contains a <code>'_'</code>, then
+ * this and everything following it is trimmed.</li>
+ * <li>If the variant is non-empty, it is converted to
+ * an empty string.</li>
+ * <li>If the country is non-empty, it is converted to
+ * an empty string.</li>
+ * <li>If the language is non-empty, it is converted to
+ * an empty string (forming {@link java.util.Locale#ROOT})</li>
+ * </ol>
+ * <p>
+ * The base fallback locale is {@link java.util.Locale#ROOT}.
+ * </p>
+ *
+ * @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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.locale package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.locale</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 <code>n</code> 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 <code>a / b</code> 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 <code>n</code> 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 <code>a * b</code> 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 <code>a</code> with
+ * the <code>n</code> digits.
+ *
+ * @param n the number of digits
+ * @param a the fixed point value
+ *
+ * @return <code>ceil(a)</code> 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 <code>a</code> with
+ * <code>n</code> digits.
+ *
+ * @param n the number of digits
+ * @param a the fixed point value
+ *
+ * @return <code>floor(a)</code> 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 <code>a</code> with
+ * the <code>n</code> digits.
+ *
+ * @param n the number of digits
+ * @param a the fixed point value
+ *
+ * @return <code>round(a)</code> as fixed point value
+ */
+ public static int round(int n, int a)
+ {
+ return (a + (1 << (n - 1))) & -(1 << n);
+ }
+
+ /**
+ * Returns the fixed point value <code>a</code> with <code>n</code> digits
+ * as float.
+ *
+ * @param n the number of digits
+ * @param a the fixed point value
+ *
+ * @return the float value of <code>a</code>
+ */
+ public static float floatValue(int n, int a)
+ {
+ return ((float) a) / (1 << n);
+ }
+
+ /**
+ * Returns the fixed point value <code>a</code> with <code>n</code> digits
+ * as double.
+ *
+ * @param n the number of digits
+ * @param a the fixed point value
+ *
+ * @return the double value of <code>a</code>
+ */
+ 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 <code>a</code> with <code>n</code> 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 <code>a</code> with <code>n</code> 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
+ * <code>a</code>. 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 <per@bothner.com>.
+
+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&lt;y, x==y, or x&gt;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&lt;y, x==y, or x&gt;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 &lt; count &lt; 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 &lt;= count &lt; 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] &gt;&gt; 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 &lt; count &lt; 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 &amp; (1&lt;&lt;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 &amp; (1&lt;&lt;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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.math package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.math</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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<String> imageTypes
+ = new HashSet<String>(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<Proxy> proxies = new ArrayList<Proxy>();
+
+ 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<Proxy> 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<InetAddress>
+{
+ 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<String> headerFieldKeys;
+ private Vector<String> headerFieldValues;
+
+ public HeaderFieldHelper()
+ {
+ this (10);
+ }
+
+ public HeaderFieldHelper (int size)
+ {
+ headerFieldKeys = new Vector<String> (size);
+ headerFieldValues = new Vector<String> (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<String, String> getHeaderFields()
+ {
+ HashMap<String, String> headers = new HashMap<String, String>();
+ 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<URL, Set<String>> prefixes
+ = new LinkedHashMap<URL, Set<String>>();
+
+ /**
+ * 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<String> values = new HashSet<String>();
+
+ // 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<URL, Set<String>> 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 <code>IllegalBlockingModeException</code> if the
+ * associated channel is in non-blocking mode, <i>except</i>
+ * 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 <code>true</code> for stream sockets, <code>false</code> 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.
+ *
+ * <p>
+ * Note that if the SO_LINGER option is set on this socket, then the
+ * operation could block.
+ * </p>
+ *
+ * @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 <code>InputStream</code> for
+ * sockets. It in an internal only class used by <code>PlainSocketImpl</code>.
+ *
+ * @author Nic Ferrier <nferrier@tapsellferrier.co.uk>
+ */
+ 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 <code>PlainSocketImpl</code> to be the
+ * <code>OutputStream</code> subclass returned by its
+ * <code>getOutputStream method</code>. It expects only to be used in that
+ * context.
+ *
+ * @author Nic Ferrier <nferrier@tapsellferrier.co.uk>
+ */
+ 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 <code>FileURLLoader</code> is a type of <code>URLLoader</code>
+ * 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
+ * <code>File.separatorChar</code>
+ *
+ * @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 <code>JarURLLoader</code> is a type of <code>URLLoader</code>
+ * 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<URLLoader> 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<URL, Set<String>> 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<URLLoader>();
+ Iterator<Map.Entry<URL, Set<String>>> it = indexMap.entrySet().iterator();
+ while (it.hasNext())
+ {
+ Map.Entry<URL, Set<String>> entry = it.next();
+ URL subURL = entry.getKey();
+ Set<String> 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<URLLoader>();
+ 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<URLLoader> 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<URLLoader> 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 <code>Resource</code> represents a resource in some
+ * <code>URLLoader</code>. It also contains all information (e.g.,
+ * <code>URL</code>, <code>CodeSource</code>, <code>Manifest</code> and
+ * <code>InputStream</code>) that is necessary for loading resources
+ * and creating classes from a <code>URL</code>.
+ */
+public abstract class Resource
+{
+ final URLLoader loader;
+
+ public Resource(URLLoader loader)
+ {
+ this.loader = loader;
+ }
+
+ /**
+ * Returns the non-null <code>CodeSource</code> associated with
+ * this resource.
+ */
+ public CodeSource getCodeSource()
+ {
+ Certificate[] certs = getCertificates();
+ if (certs == null)
+ return loader.noCertCodeSource;
+ else
+ return new CodeSource(loader.baseURL, certs);
+ }
+
+ /**
+ * Returns <code>Certificates</code> 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 <code>URL</code> that can be used to access this resource.
+ */
+ public abstract URL getURL();
+
+ /**
+ * Returns the size of this <code>Resource</code> in bytes or
+ * <code>-1</code> when unknown.
+ */
+ public abstract int getLength();
+
+ /**
+ * Returns the non-null <code>InputStream</code> 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 <code>URLLoader</code> contains all logic to load resources from a
+ * given base <code>URL</code>.
+ */
+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 <code>CodeSource</code> without any associated certificates.
+ * It is common for classes to not have certificates associated
+ * with them. If they come from the same <code>URLLoader</code>
+ * then it is safe to share the associated <code>CodeSource</code>
+ * between them since <code>CodeSource</code> 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 <code>Class</code> loaded by this
+ * <code>URLLoader</code>, or <code>null</code> 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 <code>Class</code> objects.
+ */
+ public Class getClass(String className)
+ {
+ return null;
+ }
+
+ /**
+ * Returns a <code>Resource</code> loaded by this
+ * <code>URLLoader</code>, or <code>null</code> when no
+ * <code>Resource</code> with the given name exists.
+ */
+ public abstract Resource getResource(String s);
+
+ /**
+ * Returns the <code>Manifest</code> associated with the
+ * <code>Resource</code>s loaded by this <code>URLLoader</code> or
+ * <code>null</code> there is no such <code>Manifest</code>.
+ */
+ public Manifest getManifest()
+ {
+ return null;
+ }
+
+ /**
+ * Return a list of new URLLoader objects representing any
+ * class path entries added by this container.
+ */
+ public ArrayList<URLLoader> 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<URLStreamHandlerFactory, HashMap<String, URLStreamHandler>> factoryCache
+ = new HashMap<URLStreamHandlerFactory, HashMap<String, URLStreamHandler>>(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<String, URLStreamHandler>(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<String, URLStreamHandler> 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 <i>path</i> is <tt>null</tt>.
+ */
+ 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.net package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.net</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 <code>directoryListing</code> 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 <code>Permission</code> object representing the
+ * permissions required to access this URL. This method returns a
+ * <code>java.io.FilePermission</code> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.net.protocol.file package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.net.protocol.file</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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:
+ * <ul>
+ * <li>STAT, HELP, SITE, SMNT, and ACCT commands are not supported.</li>
+ * <li>the TYPE command does not allow alternatives to the default bytesize
+ * (Non-print), and local bytesize is not supported.</li>
+ * </ul>
+ *
+ * @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 &lt;=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 &lt;=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 <code>store</code> or
+ * <code>append</code>.
+ * @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<String> 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<String> ret = new ArrayList<String>();
+ 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<String, List<String>> getRequestProperties()
+ {
+ Map<String, List<String>> map = new HashMap<String, List<String>>();
+ addRequestPropertyValue(map, "passive");
+ addRequestPropertyValue(map, "representationType");
+ addRequestPropertyValue(map, "fileStructure");
+ addRequestPropertyValue(map, "transferMode");
+ return map;
+ }
+
+ private void addRequestPropertyValue(Map<String, List<String>> map,
+ String key)
+ {
+ String value = getRequestProperty(key);
+ ArrayList<String> l = new ArrayList<String>();
+ 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.net.protocol.ftp package.
+ 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. -->
+
+<html>
+<head><title>GNU Classpath - gnu.java.net.protocol.ftp</title></head>
+
+<body>
+
+<p>
+This package contains an FTP client. It can handle both active and passive
+mode connections and the various transfer modes and representation types.
+</p>
+
+<p>
+Interaction with the server is via a simple stream interface. Only one
+concurrent stream (input or output) is supported.
+</p>
+
+<p>
+The control connection to the server can be protected using TLS
+(the starttls method).
+</p>
+
+</body>
+</html>
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<HandshakeCompletedListener> 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<String, Integer> 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<HandshakeCompletedListener>(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<HTTPConnection> connectionPool
+ = new LinkedList<HTTPConnection>();
+
+ /**
+ * 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 <code>abs_path</code> 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<String, Integer>();
+ }
+ 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, <i>or</i> RFC 1036, <i>or</i> the
+ * ANSI C <code>asctime()</code> 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 <code>format(Date)</code>
+ * 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<String, List<String>> getRequestProperties()
+ {
+ if (connected)
+ throw new IllegalStateException("Already connected");
+
+ Map<String, List<String>> 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<String,List<String>> getHeaderFields()
+ {
+ if (!connected)
+ {
+ try
+ {
+ connect();
+ }
+ catch (IOException e)
+ {
+ return null;
+ }
+ }
+ Map<String,List<String>> 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<Headers.HeaderElement>
+{
+ /**
+ * A list of HeaderElements
+ */
+ private final ArrayList<HeaderElement> headers
+ = new ArrayList<HeaderElement>();
+
+ /**
+ * 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<HeaderElement> 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 <code>null</code> 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 <code>-1</code> 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 <code>-1</code> 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 <code>null</code> 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<HeaderElement> 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<HeaderElement> 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).
+ *
+ * <p>
+ * The returned map is modifiable. Changing it will not effect this
+ * collection of Headers in any way.</p>
+ *
+ * @return a Map containing all the headers.
+ */
+ public Map<String,List<String>> getAsMap()
+ {
+ LinkedHashMap<String,List<String>> m = new LinkedHashMap<String,List<String>>();
+ for (Iterator<HeaderElement> it = headers.iterator(); it.hasNext(); )
+ {
+ HeaderElement e = it.next();
+ ArrayList<String> l = (ArrayList<String>)m.get(e.name);
+ if (l == null)
+ {
+ l = new ArrayList<String>(1);
+ l.add(e.value);
+ m.put(e.name, l);
+ }
+ else
+ l.add(0, e.value);
+ }
+ for (Iterator<Map.Entry<String,List<String>>> it = m.entrySet().iterator(); it.hasNext(); )
+ {
+ Map.Entry<String,List<String>> me = it.next();
+ List<String> 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 <code>null</code> 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 <code>null</code> 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<String, ResponseHeaderHandler> 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<String, ResponseHeaderHandler>();
+ }
+
+ /**
+ * 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.
+ * <dl>
+ * <dt><code>1xx</code></dt> <dd>Informational response</dd>
+ * <dt><code>2xx</code></dt> <dd>Success</dd>
+ * <dt><code>3xx</code></dt> <dd>Redirection</dd>
+ * <dt><code>4xx</code></dt> <dd>Client error</dd>
+ * <dt><code>5xx</code></dt> <dd>Server error</dd>
+ * </dl>
+ */
+ 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 <code>true</code> if, <code>false</code> otherwise.
+ */
+ public boolean isRedirect()
+ {
+ return (code != 304 && getCodeClass() == 3);
+ }
+
+ /**
+ * Tests whether this response indicates an error.
+ * Errors are the response codes <code>4xx</code> - Client error and
+ * <code>5xx</code> - Server error.
+ *
+ * @return <code>true</code> if, <code>false</code> 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<String, Map<String, Cookie>> cookies;
+
+ /**
+ * Constructor.
+ */
+ public SimpleCookieManager()
+ {
+ cookies = new HashMap<String, Map<String, Cookie>>();
+ }
+
+ public void setCookie(Cookie cookie)
+ {
+ String domain = cookie.getDomain();
+ Map<String, Cookie> map = cookies.get(domain);
+ if (map == null)
+ {
+ map = new HashMap<String, Cookie>();
+ 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<Cookie> matches = new ArrayList<Cookie>();
+ 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<Cookie> matches, String domain,
+ boolean secure, String path, Date now)
+ {
+ Map<String, Cookie> map = cookies.get(domain);
+ if (map != null)
+ {
+ ArrayList<String> expired = new ArrayList<String>();
+ for (Map.Entry<String, Cookie> 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<String> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.net.protocol.http package.
+ 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. -->
+
+<html>
+<head><title>GNU Classpath - gnu.java.net.protocol.http</title></head>
+
+<body>
+
+<p>
+This package contains an HTTP/1.1 client, as described in RFC 2616.
+It supports the following features:
+<ul>
+<li>Persistent connections</li>
+<li>Basic and Digest authentication (RFC 2617)</li>
+<li>HTTPS</li>
+<li>HTTP proxies</li>
+<li>HTTP/1.0 compatibility</li>
+<li>Support for WebDAV methods and other HTTP extensions</li>
+<li>Automatic decoding of the chunked transfer-coding</li>
+<li>Parsing of HTTP date headers</li>
+<li>Support for the 100-continue expectation</li>
+</ul>
+</p>
+
+<p>
+The API is similar to the <a href='http://www.webdav.org/neon/'>neon</a>
+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 <code>dispatch</code> 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.
+</p>
+
+<p>
+An URL stream handler is provided, supporting the full HttpURLConnection
+specification.
+</p>
+
+</body>
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<URL, JarFile> cache
+ = new Hashtable<URL, JarFile>();
+ 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<String> tokens = new ArrayList<String>();
+ 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<String> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.net.protocol.jar package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.net.protocol.jar</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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.
+ *
+ * <p>
+ * This is a bridge between NIO <-> IO character decoding.
+ * </p>
+ *
+ * @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 <code>IllegalBlockingModeException</code> if
+ * we are in non-blocking mode, <i>except</i> 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 + " <<invalid>> ]";
+ 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 <code>kqueue</code>
+ * 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/*<Integer,KqueueSelectionKeyImpl>*/ keys;
+ private HashSet/*<KqueueSelectionKeyImpl>*/ 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/*<KqueueSelectionKeyImpl>*/();
+ 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/*<KqueueSelectionKeyImpl>*/(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 <code>struct kevent</code> on this system.
+ *
+ * @return The size of <code>struct kevent</code>.
+ */
+ 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 <code>struct kevent</code>s 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 <code>events</code>,
+ * 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 <code>events</code> 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 <code>struct
+ * kevent</code>s) in that key's {@link KqueueSelectionKeyImpl#nstate}
+ * buffer, and place the pointer of the key in the <code>udata</code> field
+ * of that structure. This method fetches that pointer from the given
+ * buffer (assumed to be a <code>struct kqueue</code>) and returns it.
+ *
+ * @param nstate The buffer containing the <code>struct kqueue</code> 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 <code>struct kevent</code>, looking
+ * at its operation (the input is assumed to have been returned via a
+ * previous call to <code>kevent</code>), 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<SelectionKey> keys;
+ private Set<SelectionKey> 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<SelectionKey> ();
+ selected = new HashSet<SelectionKey> ();
+ }
+
+ 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<SelectionKey> 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<SelectionKey> 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<SelectionKey> 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<SelectionKey> 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<SelectionKey> ckeys = cancelledKeys ();
+ synchronized (ckeys)
+ {
+ Iterator<SelectionKey> 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 <mike@middlesoft.co.uk>
+ *
+ */
+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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.nio.channels package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.nio.channels</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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<String,String> canonicalNames;
+
+ static {
+ canonicalNames = new HashMap<String,String>();
+ 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<String, String> 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<String, Charset> 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<String,String> ();
+ charsets = new HashMap<String,Charset> ();
+
+ // 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<Charset> 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.
+ *
+ * <p>The lookup is therefore case-insensitive.</p>
+ *
+ * @returns The Charset having <code>charsetName</code>
+ * 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.
+ *
+ * <p>All names are converted to lower-case</p>.
+ *
+ * @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<String> 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<Provider>()
+ {
+ 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.
+ *
+ * <p> UTF-8 references:
+ * <ul>
+ * <li> <a href="http://ietf.org/rfc/rfc2279.txt">RFC 2279</a>
+ * <li> The <a href="http://www.unicode.org/unicode/standard/standard.html">
+ * Unicode standard</a> and
+ * <a href="http://www.unicode.org/versions/corrigendum1.html">
+ * Corrigendum</a>
+ * </ul>
+ *
+ * @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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.nio.charset package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.nio.charset</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.nio package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.nio</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.rmi.dgc package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.rmi.dgc</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.rmi package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.rmi</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.rmi.registry package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.rmi.registry</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.rmi.server package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.rmi.server</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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.
+ * <p>
+ * 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 <i>algorithm</i> for service <i>service</i>
+ * from <i>provider</i>. 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 <i>algorithm</i> for service <i>service</i>
+ * from <i>provider</i>, passing <i>initArgs</i> 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
+ * <code>null</code> or if either <code>service</code>, or
+ * <code>algorithm</code> 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.
+ *
+ * <p>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).
+ *
+ * <p>OIDs can be represented in a variety of ways, including the
+ * dotted-decimal form we use here.
+ *
+ * <p>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 <i>components</i> 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 <i>components</i> 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 <i>o</i> 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 <em>policy file</em>.
+ *
+ * <p>The approximate syntax of policy files is:</p>
+ *
+ * <pre>
+ * 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;
+ * </pre>
+ *
+ * <p>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 <code>${property-name}</code> will be
+ * replaced with <code>System.getProperty("property-name")</code> in
+ * quoted strings.</p>
+ *
+ * <p>This class will load the following files when created or
+ * refreshed, in order:</p>
+ *
+ * <ol>
+ * <li>The file <code>${java.home}/lib/security/java.policy</code>.</li>
+ * <li>All URLs specified by security properties
+ * <code>"policy.file.<i>n</i>"</code>, for increasing <i>n</i>
+ * starting from 1. The sequence stops at the first undefined
+ * property, so you must set <code>"policy.file.1"</code> if you also
+ * set <code>"policy.file.2"</code>, and so on.</li>
+ * <li>The URL specified by the property
+ * <code>"java.security.policy"</code>.</li>
+ * </ol>
+ *
+ * @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 "<keystore-path>" [',' "<keystore-type>"] ';'
+ 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 <code>"${property-name}"</code> into
+ * <code>System.getProperty("property-name")</code>.
+ */
+ 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 <code>key</code>.
+ *
+ * @param key the case-insensitive, non-null and non-empty name of a
+ * configuration property.
+ * @return the string representation of the designated property, or
+ * <code>null</code> if such property is not yet set, or
+ * <code>key</code> 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 <code>key</code>.
+ */
+ 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 <code>true</code> if the default PRNG produces the same bit
+ * stream with every VM instance. Returns <code>false</code> 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 <code>true</code> if the cipher implementations check for weak
+ * and semi-weak keys. Returns <code>false</code> 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 <code>true</code> if the RSA decryption primitive includes a
+ * blinding operation. Returns <code>false</code> 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 <code>true</code> 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 <code>true</code> 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 <code>true</code> 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 <i>names</i> and <i>literals</i> 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<? extends Permission> 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:
+ * <code>
+ * GetPropertyAction action = new GetPropertyAction("http.proxyPort");
+ * String port = AccessController.doPrivileged(action);
+ * </code>
+ */
+public class GetPropertyAction implements PrivilegedAction<String>
+{
+ 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:
+ * <code>
+ * GetSecurityPropertyAction action = new GetSecurityPropertyAction("javax.net.ssl.trustStorePassword");
+ * String passwd = AccessController.doPrivileged(action);
+ * </code>
+ */
+public class GetSecurityPropertyAction implements PrivilegedAction<String>
+{
+ 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:
+ * <code>
+ * Field dataField = cl.getDeclaredField("data");
+ * AccessController.doPrivileged(new SetAccessibleAction(dataField));
+ * </code>
+ */
+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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.security.action package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.security.action</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.security.ber package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.security.ber</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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:
+ *
+ * <pre> 00010101 11101101 11010xxx</pre>
+ *
+ * <p>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 <i>ignoredBits</i>.
+ * @throws IllegalArgumentException If <i>ignoredBits</i> is negative
+ * or greater than 7.
+ * @throws NullPointerException If <i>bytes</i> 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 <i>ignoredBits</i>.
+ * @throws IllegalArgumentException If <i>ignoredBits</i> is negative
+ * or greater than 7.
+ * @throws NullPointerException If <i>bytes</i> 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 <i>ignoredBits</i> is negative
+ * or greater than 7.
+ * @throws NullPointerException If <i>bytes</i> 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 <i>ignoredBits</i> is negative
+ * or greater than 7.
+ * @throws NullPointerException If <i>bytes</i> 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 <i>bytes</i> 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 <i>bytes</i> 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 <code>true</code> 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.
+ *
+ * <p>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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.security.der package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.security.der</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 <i>blockSize</i> 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 <i>Factory</i> to instantiate message digest algorithm instances.
+ */
+public class HashFactory
+{
+ /** Trivial constructor to enforce <i>Singleton</i> 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
+ * <i>Factory</i>.
+ *
+ * @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 <i>HAVAL</i> message-digest algorithm is a variable output length, with
+ * variable number of rounds. By default, this implementation allows <i>HAVAL</i>
+ * to be used as a drop-in replacement for <i>MD5</i>.
+ * <p>
+ * References:
+ * <ol>
+ * <li>HAVAL - A One-Way Hashing Algorithm with Variable Length of Output<br>
+ * Advances in Cryptology - AUSCRYPT'92, Lecture Notes in Computer Science,<br>
+ * Springer-Verlag, 1993; <br>
+ * Y. Zheng, J. Pieprzyk and J. Seberry.</li>
+ * </ol>
+ */
+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 <code>3
+ * .. 5</code>.
+ * The default is <code>3</code>.
+ */
+ 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. <code>128</code> 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 <code>Haval</code> instance with the designated output size
+ * (in bytes). Valid output <code>size</code> values are <code>16</code>,
+ * <code>20</code>, <code>24</code>, <code>28</code> and
+ * <code>32</code>. Valid values for <code>rounds</code> are in the range
+ * <code>3..5</code> 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.
+ * <p>
+ * 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 <code>true</code> if the implementation passes a basic self-test.
+ * Returns <code>false</code> 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.
+ * <p>
+ * MD2 is not widely used. Unless it is needed for compatibility with
+ * existing systems, it is not recommended for use in new applications.
+ * <p>
+ * References:
+ * <ol>
+ * <li>The <a href="http://www.ietf.org/rfc/rfc1319.txt">MD2</a>
+ * Message-Digest Algorithm.<br>
+ * B. Kaliski.</li>
+ * <li>The <a href="http://www.rfc-editor.org/errata.html">RFC ERRATA PAGE</a>
+ * under section RFC 1319.</li>
+ * </ol>
+ */
+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 <code>BLOCK_LENGTH</code> 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
+ * <code>i</code> bytes of value <code>i</code>, where <code>i</code> is the
+ * number of bytes to fill the last block of the message to
+ * <code>BLOCK_LENGTH</code> bytes (or <code>BLOCK_LENGTH</code> 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 <code>BLOCK_LENGTH</code> bytes to the running digest.
+ *
+ * @param in the byte array to take the <code>BLOCK_LENGTH</code> 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 (<code>BLOCK_LENGTH</code> 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.
+ * <p>
+ * 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li>The <a href="http://www.ietf.org/rfc/rfc1320.txt">MD4</a>
+ * Message-Digest Algorithm.<br>
+ * R. Rivest.</li>
+ * </ol>
+ *
+ * @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 <code>0</code>, and creates a new block of <code>512</code> 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li>The <a href="http://www.ietf.org/rfc/rfc1321.txt">MD5</a> Message-
+ * Digest Algorithm.<br>
+ * R. Rivest.</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html">
+ * RIPEMD160</a>: A Strengthened Version of RIPEMD.<br>
+ * Hans Dobbertin, Antoon Bosselaers and Bart Preneel.</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.esat.kuleuven.ac.be/~bosselae/ripemd160.html">
+ * RIPEMD160</a>: A Strengthened Version of RIPEMD.<br>
+ * Hans Dobbertin, Antoon Bosselaers and Bart Preneel.</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.itl.nist.gov/fipspubs/fip180-1.htm">SECURE HASH
+ * STANDARD</a><br>
+ * Federal Information, Processing Standards Publication 180-1, 1995 April 17.
+ * </li>
+ * </ol>
+ */
+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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://ftp.ipv4.heanet.ie/pub/ietf/internet-drafts/draft-ietf-ipsec-ciph-aes-cbc-03.txt">
+ * Descriptions of SHA-256, SHA-384, and SHA-512</a>,</li>
+ * <li>http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://ftp.ipv4.heanet.ie/pub/ietf/internet-drafts/draft-ietf-ipsec-ciph-aes-cbc-03.txt">
+ * Descriptions of SHA-256, SHA-384, and SHA-512</a>,</li>
+ * <li>http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://ftp.ipv4.heanet.ie/pub/ietf/internet-drafts/draft-ietf-ipsec-ciph-aes-cbc-03.txt">
+ * Descriptions of SHA-256, SHA-384, and SHA-512</a>,</li>
+ * <li>http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * Tiger processes data in 512-bit blocks and produces a 192-bit
+ * digest.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.cs.technion.ac.il/~biham/Reports/Tiger/">Tiger: A
+ * Fast New Hash Function</a>, Ross Anderson and Eli Biham.</a></li>
+ * </ol>
+ */
+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.
+ * <p>
+ * This implementation is of Whirlpool Version 3, described in [1] last revised
+ * on May 24th, 2003.
+ * <p>
+ * <b>IMPORTANT</b>: This implementation is not thread-safe.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://planeta.terra.com.br/informatica/paulobarreto/WhirlpoolPage.html">
+ * The WHIRLPOOL Hashing Function</a>.<br>
+ * <a href="mailto:paulo.barreto@terra.com.br">Paulo S.L.M. Barreto</a> and
+ * <a href="mailto:vincent.rijmen@iaik.tugraz.at">Vincent Rijmen</a>.</li>
+ * </ol>
+ */
+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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i> (<b>SPI</b>)
+ * 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 <i>Service Provider Interface</i> (<b>SPI</b>)
+ * 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 <i>Service Provider Interface</i> (<b>SPI</b>)
+ * 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.
+ * <p>
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) 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.
+ * <p>
+ * All the abstract methods in the {@link MessageDigestSpi} class are
+ * implemented by this class and all its sub-classes.
+ * <p>
+ * 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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) <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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) <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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) <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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) <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider
+ * Interface</i> (<b>SPI</b>) 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 <i>Service Provider
+ * Interface</i> (<b>SPI</b>) 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 <i>Service Provider
+ * Interface</i> (<b>SPI</b>) 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 <i>Service Provider
+ * Interface</i> (<b>SPI</b>) 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 <i>Service Provider
+ * Interface</i> (<b>SPI</b>) 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 <i>Service Provider
+ * Interface</i> (<b>SPI</b>) 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;
+
+/**
+ * <p>The implementation of a generic {@link java.security.SecureRandom} adapter
+ * class to wrap gnu.crypto prng instances based on Message Digest algorithms.</p>
+ *
+ * <p>This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for
+ * the {@link java.security.SecureRandom} class, which provides the
+ * functionality of a cryptographically strong pseudo-random number generator.</p>
+ *
+ * <p>All the abstract methods in the {@link SecureRandomSpi} class are
+ * implemented by this class and all its sub-classes.</p>
+ */
+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";
+
+ /**
+ * <p>Trivial protected constructor.</p>
+ *
+ * @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 <i>Service Provider
+ * Interface</i> (<b>SPI</b>) 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 <i>Service Provider
+ * Interface</i> (<b>SPI</b>) 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 <i>Service Provider
+ * Interface</i> (<b>SPI</b>) 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 <i>Service Provider
+ * Interface</i> (<b>SPI</b>) 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 <i>Service Provider
+ * Interface</i> (<b>SPI</b>) 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 <i>Service Provider
+ * Interface</i> (<b>SPI</b>) 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.
+ * <p>
+ * In case the client does not explicitly initialize the KeyPairGenerator (via a
+ * call to an <code>initialize()</code> method), the GNU provider uses a
+ * default <i>modulus</i> 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 <code>2<sup>L-1</sup> &lt; p &lt; 2<sup>L</sup></code>
+ * for <code>512 &lt;= L &lt;= 1024</code> and <code>L</code> a multiple of
+ * <code>64</code>.
+ */
+ private BigInteger p;
+
+ /**
+ * A prime divisor of <code>p - 1</code>, where <code>2<sup>159</sup> &lt; q
+ * &lt; 2<sup>160</sup></code>.
+ */
+ private BigInteger q;
+
+ /**
+ * <code>g = h<sup>(p-1)</sup>/q mod p</code>, where <code>h</code> is any
+ * integer with <code>1 &lt; h &lt; p - 1</code> such that <code>h<sup>
+ * (p-1)</sup>/q mod p > 1</code> (<code>g</code> has order <code>q mod p
+ * </code>).
+ */
+ 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:
+ *
+ * <pre>
+ * DssParams ::= SEQUENCE {
+ * p INTEGER,
+ * q INTEGER,
+ * g INTEGER
+ * }
+ * </pre>
+ */
+ 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:
+ *
+ * <pre>
+ * DssParams ::= SEQUENCE {
+ * p INTEGER,
+ * q INTEGER,
+ * g INTEGER
+ * }
+ * </pre>
+ */
+ 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 <i>Service Provider Interface</i> (<b>SPI</b>)
+ * 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.
+ * <p>
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for
+ * the {@link java.security.KeyPairGenerator} class, which is used to generate
+ * pairs of public and private keys.
+ * <p>
+ * All the abstract methods in the {@link java.security.KeyPairGeneratorSpi}
+ * class are implemented by this class and all its sub-classes.
+ * <p>
+ * In case the client does not explicitly initialize the KeyPairGenerator (via a
+ * call to an <code>initialize()</code> method), the GNU provider supplies
+ * (and document) default values to be used. For example, the GNU provider uses
+ * a default <i>modulus</i> size (keysize) of 1024 bits for the DSS (Digital
+ * Signature Standard) a.k.a <i>DSA</i>.
+ */
+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.
+ * <p>
+ * In case the client does not explicitly initialize the KeyPairGenerator (via a
+ * call to an <code>initialize()</code> method), the GNU provider uses a
+ * default <i>modulus</i> 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 <i>Service Provider Interface</i> (<b>SPI</b>)
+ * 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.
+ * <p>
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) 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.
+ * <p>
+ * All the abstract methods in the {@link SignatureSpi} class are implemented by
+ * this class and all its sub-classes.
+ * <p>
+ * 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 <i>Raw</i> encoding format. */
+ int RAW_FORMAT = Registry.RAW_ENCODING_ID;
+
+ /** Constant identifying the <i>X.509</i> encoding format. */
+ int X509_FORMAT = Registry.X509_ENCODING_ID;
+
+ /** Constant identifying the <i>PKCS#8</i> encoding format. */
+ int PKCS8_FORMAT = Registry.PKCS8_ENCODING_ID;
+
+ /**
+ * Constant identifying the <i>ASN.1</i> encoding format: a combined encoding
+ * of <i>X.509</i> for public keys, and <i>PKCS#8</i> 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 <i>Factory</i> 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
+ * <code>/</code> and the canonical name of the encoding format.
+ * <p>
+ * <b>IMPORTANT</b>: 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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
+ * <code>null</code> 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
+ * <code>null</code> 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
+ * <code>null</code> 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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
+ * <i>Factory</i>. 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: <code>p</code>,
+ * <code>q</code> and <code>g</code>.
+ * <p>
+ * According to the JDK, cryptographic <i>Keys</i> all have a <i>format</i>.
+ * The format used in this implementation is called <i>Raw</i>, 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 <code>getEncoded()</code> methods of each of the private and
+ * public keys.
+ * <p>
+ * <b>IMPORTANT</b>: Under certain circumstances (e.g. in an X.509 certificate
+ * with inherited AlgorithmIdentifier's parameters of a SubjectPublicKeyInfo
+ * element) these three MPIs may be <code>null</code>.
+ *
+ * @see DSSPrivateKey#getEncoded
+ * @see DSSPublicKey#getEncoded
+ */
+public abstract class DSSKey
+ implements Key, DSAKey
+{
+ /**
+ * A prime modulus, where
+ * <code>2<sup>L-1</sup> &lt; p &lt; 2<sup>L</sup></code> for
+ * <code>512 &lt;= L &lt;= 1024</code> and <code>L</code> a multiple of
+ * <code>64</code>.
+ */
+ protected final BigInteger p;
+
+ /**
+ * A prime divisor of <code>p - 1</code>, where
+ * <code>2<sup>159</sup> &lt; q
+ * &lt; 2<sup>160</sup></code>.
+ */
+ protected final BigInteger q;
+
+ /**
+ * <code>g = h<sup>(p-1)</sup>/q mod p</code>, where <code>h</code> is
+ * any integer with <code>1 &lt; h &lt; p - 1</code> such that <code>h<sup>
+ * (p-1)</sup>/q mod p > 1</code> (<code>g</code>
+ * has order <code>q mod p
+ * </code>).
+ */
+ 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 <code>p</code>.
+ * @param q the DSS parameter <code>q</code>.
+ * @param g the DSS parameter <code>g</code>.
+ */
+ 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 <code>true</code> if the designated object is an instance of
+ * {@link DSAKey} and has the same DSS (Digital Signature Standard) parameter
+ * values as this one.
+ * <p>
+ * Always returns <code>false</code> if the MPIs of this key are
+ * <i>inherited</i>. 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 <code>true</code> 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 <code>true</code> if <code>p</code>, <code>q</code> and
+ * <code>g</code> are all <code>null</code>. Returns
+ * <code>false</code> 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).
+ * <p>
+ * References:
+ * <p>
+ * <a href="http://www.itl.nist.gov/fipspubs/fip186.htm">Digital Signature
+ * Standard (DSS)</a>, 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 <code>p</code>, <code>q</code> and <code>g</code>
+ * 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}:
+ * <ol>
+ * <li>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 <code>512</code> and
+ * <code>1024</code>, and is of the form <code>512 + 64 * n</code>. In
+ * addition, a new paramter set will always be generated; i.e. no pre-
+ * computed values are used.</li>
+ * <li>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 <code>512</code>, <code>768</code> and <code>1024</code>. Any
+ * other value, of the modulus length, even if between <code>512</code> and
+ * <code>1024</code>, and of the form <code>512 + 64 * n</code>, will
+ * cause an {@link IllegalArgumentException} to be thrown. When those modulus
+ * length (<code>512</code>, <code>768</code>, and <code>1024</code>)
+ * are specified, the paramter set is always the same.</li>
+ * <li>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 <code>512</code>,
+ * <code>768</code>, or <code>1024</code>.</li>
+ * </ol>
+ * 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 <i>L</i> 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 <code>p</code>, <code>q</code>, and <code>g</code>
+ * values. The default is to generate these values or use pre-computed ones,
+ * depending on the value of the <code>USE_DEFAULTS</code> 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
+ * <code>512 + 64j</code>.
+ */
+ 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:
+ * <ol>
+ * <li>XSEED = optional user input.</li>
+ * <li>XVAL = (XKEY + XSEED) mod 2<sup>b</sup>.</li>
+ * <li>x = G(t, XVAL) mod q.</li>
+ * <li>XKEY = (1 + XKEY + x) mod 2<sup>b</sup>.</li>
+ * </ol>
+ * <p>
+ * Where <code>b</code> is the length of a secret b-bit seed-key (XKEY).
+ * <p>
+ * 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 <i>PrivateKeyInfo</i> representation of a DSA
+ * private key. The ASN.1 specification is as follows:
+ *
+ * <pre>
+ * 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
+ * }
+ * </pre>
+ *
+ * @return the DER encoded form of the ASN.1 representation of the
+ * <i>PrivateKeyInfo</i> 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
+ * <i>PrivateKeyInfo</i> material fed as <code>input</code>.
+ * @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
+ * <i>Raw</i> 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 <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for a DSA public key, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_DSS_PUBLIC_KEY},
+ * <li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>p</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>p</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>q</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>q</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>g</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>g</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>y</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>y</code>,
+ * </li>
+ * </ol>
+ *
+ * @param key the key to encode.
+ * @return the <i>Raw</i> 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 <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for a DSA private key, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_DSS_PRIVATE_KEY},
+ * <li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>p</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>p</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>q</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>q</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>g</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>g</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DSA parameter
+ * <code>x</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSA parameter <code>x</code>,
+ * </li>
+ * </ol>
+ *
+ * @param key the key to encode.
+ * @return the <i>Raw</i> 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 <i>SubjectPublicKeyInfo</i> representation of a
+ * DSA public key. The ASN.1 specification, as defined in RFC-3280, and
+ * RFC-2459, is as follows:
+ *
+ * <pre>
+ * 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
+ * }
+ * </pre>
+ * <p>
+ * 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 <i>inherited</i> from another
+ * certificate. This implementation, encodes a <i>NULL</i> element as the DER
+ * value of the parameters field when such is the case.
+ * <p>
+ * The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
+ * DER-encoded form of the DSA public key as an INTEGER.
+ *
+ * <pre>
+ * DSAPublicKey ::= INTEGER -- public key, Y
+ * </pre>
+ *
+ * @param key the {@link PublicKey} instance to encode. MUST be an instance of
+ * {@link DSSPublicKey}.
+ * @return the ASN.1 representation of the <i>SubjectPublicKeyInfo</i> in an
+ * X.509 certificate.
+ * @throw InvalidParameterException if <code>key</code> 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
+ * <i>SubjectPublicKeyInfo</i> 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 <code>0 &lt; x &lt;
+ * q</code>.
+ */
+ 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 <code>p-1</code>.
+ * @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
+ * <sub>p</sub></code>.
+ * @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 <code>DSSPrivateKey</code> 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 <code>p-1</code>.
+ * @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
+ * <sub>p</sub></code>.
+ * @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 <code>encodePrivateKey()</code>
+ * 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
+ * <code>k</code>, 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 <code>true</code> 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 <code>true</code> 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
+{
+ /**
+ * <code>y = g<sup>x</sup> mod p</code> where <code>x</code> 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 <code>p-1</code>.
+ * @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
+ * <sub>p</sub></code>.
+ * @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 <code>DSSPublicKey</code> 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 <code>p-1</code>.
+ * @param g a generator of the unique cyclic group <code>Z<sup>*</sup>
+ * <sub>p</sub></code>.
+ * @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 <code>encodePublicKey()</code>
+ * 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
+ * <code>k</code>, 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 <code>true</code> 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 <code>true</code> 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.
+ * <p>
+ * References:
+ * <p>
+ * <a href="http://www.itl.nist.gov/fipspubs/fip186.htm">Digital Signature
+ * Standard (DSS)</a>, 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 <code>p</code>, <code>q</code>, and
+ * <code>g</code> parameters only when <code>L</code> (the modulus length)
+ * is not one of the following: <code>512</code>, <code>768</code> and
+ * <code>1024</code>. For those values of <code>L</code>, this
+ * implementation uses pre-computed values of <code>p</code>,
+ * <code>q</code>, and <code>g</code> given in the document <i>CryptoSpec</i>
+ * included in the security guide documentation of the standard JDK
+ * distribution.
+ * <p>
+ * The DSS requires two primes , <code>p</code> and <code>q</code>,
+ * satisfying the following three conditions:
+ * <ul>
+ * <li><code>2<sup>159</sup> &lt; q &lt; 2<sup>160</sup></code></li>
+ * <li><code>2<sup>L-1</sup> &lt; p &lt; 2<sup>L</sup></code> for a
+ * specified <code>L</code>, where <code>L = 512 + 64j</code> for some
+ * <code>0 &lt;= j &lt;= 8</code></li>
+ * <li>q divides p - 1.</li>
+ * </ul>
+ * 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 <i>SEED</i> to construct a
+ * prime, <code>q</code>, in the range 2<sup>159</sup> &lt; q &lt; 2<sup>160</sup>.
+ * Once this is accomplished, the same <i>SEED</i> value is used to construct
+ * an <code>X</code> in the range <code>2<sup>L-1
+ * </sup> &lt; X &lt; 2<sup>L</sup>. The prime, <code>p</code>, is then
+ * formed by rounding <code>X</code> to a number congruent to <code>1 mod
+ * 2q</code>. In this implementation we use the same <i>SEED</i> 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 <code>n</code>.
+ * @param e the public exponent <code>e</code>.
+ */
+ 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 <code>n</code>.
+ *
+ * @return the modulus <code>n</code>.
+ */
+ public BigInteger getN()
+ {
+ return n;
+ }
+
+ /**
+ * Returns the public exponent <code>e</code>.
+ *
+ * @return the public exponent <code>e</code>.
+ */
+ public BigInteger getPublicExponent()
+ {
+ return getE();
+ }
+
+ /**
+ * Same as {@link #getPublicExponent()}.
+ *
+ * @return the public exponent <code>e</code>.
+ */
+ public BigInteger getE()
+ {
+ return e;
+ }
+
+ /**
+ * Returns <code>true</code> 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 <code>true</code> 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
+ * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
+ * Primitive specification and supporting documentation.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ */
+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 <code>GnuRSAPrivateKey</code> 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 <code>GnuRSAPrivateKey</code> 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 <code>p</code>
+ * and <code>q</code>.
+ * @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
+ * <code>p</code> and <code>q</code>, satisfying
+ * <code>e * dP = 1 (mod p-1)</code>.
+ * @param dQ the second prime's exponent. A positive integer less than
+ * <code>p</code> and <code>q</code>, satisfying
+ * <code>e * dQ = 1 (mod p-1)</code>.
+ * @param qInv the Chinese Remainder Theorem coefiicient. A positive integer
+ * less than <code>p</code>, satisfying
+ * <code>q * qInv = 1 (mod p)</code>.
+ */
+ 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 <code>encodePrivateKey()</code>
+ * 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
+ * <code>k</code>, 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 <code>true</code> 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 <code>true</code> 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
+ * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
+ * Primitive specification and supporting documentation.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ */
+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 <code>GnuRSAPublicKey</code> 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 <code>encodePublicKey()</code>
+ * 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
+ * <code>k</code>, 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 <code>true</code> 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 <code>true</code> 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.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a
+ * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
+ * RSA-PSS Signature Scheme with Appendix</a>, part B. Primitive specification
+ * and supporting documentation. Jakob Jonsson and Burt Kaliski. </li>
+ * <li><a href="http://www.cacr.math.uwaterloo.ca/hac/">Handbook of Applied
+ * Cryptography</a>, Alfred J. Menezes, Paul C. van Oorschot and Scott A.
+ * Vanstone. Section 11.3 RSA and related signature schemes.</li>
+ * </ol>
+ */
+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 <code>n</code>, and <code>e</code> values. The
+ * default is to generate <code>n</code> and use a fixed value for
+ * <code>e</.code> (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");
+ }
+
+ /**
+ * <p>
+ * The algorithm used here is described in <i>nessie-pss-B.pdf</i> document
+ * which is part of the RSA-PSS submission to NESSIE.
+ * </p>
+ *
+ * @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 <i>PrivateKeyInfo</i> representation of an RSA
+ * private key. The ASN.1 specification is as follows:
+ * <pre>
+ * PrivateKeyInfo ::= SEQUENCE {
+ * version INTEGER, -- MUST be 0
+ * privateKeyAlgorithm AlgorithmIdentifier,
+ * privateKey OCTET STRING
+ * }
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ * </pre>
+ * <p>
+ * As indicated in RFC-2459: "The parameters field shall have ASN.1 type NULL
+ * for this algorithm identifier.".
+ * <p>
+ * The <i>privateKey</i> field, which is an OCTET STRING, contains the
+ * DER-encoded form of the RSA private key defined as:
+ * <pre>
+ * 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
+ * }
+ * </pre>
+ *
+ * @return the DER encoded form of the ASN.1 representation of the
+ * <i>PrivateKeyInfo</i> 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
+ * <i>PrivateKeyInfo</i> material fed as <code>input</code>.
+ * @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 <i>Raw</i>
+ * 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
+ * <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for an RSA public key, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_RSA_PUBLIC_KEY},</li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the RSA parameter
+ * <code>n</code> (the modulus) in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the RSA parameter <code>n</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the RSA parameter
+ * <code>e</code> (the public exponent) in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the RSA parameter <code>e</code>.
+ * </li>
+ * </ol>
+ *
+ * @param key the key to encode.
+ * @return the <i>Raw</i> 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
+ * <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for an RSA private key, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_RSA_PRIVATE_KEY},</li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the RSA parameter
+ * <code>p</code> (the first prime factor of the modulus) in internet order,
+ * </li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the RSA parameter <code>p</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the RSA parameter
+ * <code>q</code> (the second prime factor of the modulus) in internet
+ * order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the RSA parameter <code>q</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the RSA parameter
+ * <code>e</code> (the public exponent) in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the RSA parameter <code>e</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the RSA parameter
+ * <code>d</code> (the private exponent) in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the RSA parameter <code>d</code>,
+ * </li>
+ * </ol>
+ *
+ * @param key the key to encode.
+ * @return the <i>Raw</i> 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 <i>SubjectPublicKeyInfo</i> representation of an
+ * RSA public key. The ASN.1 specification, as defined in RFC-3280, and
+ * RFC-2459, is as follows:
+ *
+ * <pre>
+ * SubjectPublicKeyInfo ::= SEQUENCE {
+ * algorithm AlgorithmIdentifier,
+ * subjectPublicKey BIT STRING
+ * }
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL
+ * }
+ * </pre>
+ * <p>
+ * As indicated in RFC-2459: "The parameters field shall have ASN.1 type NULL
+ * for this algorithm identifier.".
+ * <p>
+ * The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
+ * DER-encoded form of the RSA public key defined as:
+ *
+ * <pre>
+ * RSAPublicKey ::= SEQUENCE {
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER -- e
+ * }
+ * </pre>
+ *
+ * @param key the {@link PublicKey} instance to encode. MUST be an instance of
+ * {@link GnuRSAPublicKey}.
+ * @return the ASN.1 representation of the <i>SubjectPublicKeyInfo</i> in an
+ * X.509 certificate.
+ * @throw InvalidParameterException if <code>key</code> 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
+ * <i>SubjectPublicKeyInfo</i> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.security package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.security</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 <code>PKCS7Data</code> 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:
+ *
+ * <pre>
+ * 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
+ * </pre>
+ *
+ * <p>(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).</p>
+ */
+ 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 <code>PKCS7SignedData</code> 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 <code>PKCS7SignedData</code>
+ * 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.
+ * <p>
+ * A SignerInfo is a structure with the following ASN.1 syntax:
+ * <pre>
+ * 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
+ * </pre>
+ */
+ 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 <code>SignerInfo</code> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.security.pkcs package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.security.pkcs</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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.
+ * <p>
+ * The [HAC] defines a PRNG (as implemented in this library) as follows:
+ * <ul>
+ * <li>"5.6 Definition: A pseudorandom bit generator (PRBG) is said to pass the
+ * <em>next-bit test</em> if there is no polynomial-time algorithm which, on
+ * input of the first <code>L</code> bits of an output sequence <code>S</code>,
+ * can predict the <code>(L+1)</code><sup>st</sup> bit of <code>S</code> with a
+ * probability significantly greater than <code>1/2</code>."</li>
+ * <li>"5.8 Definition: A PRBG that passes the <em>next-bit test</em>
+ * (possibly under some plausible but unproved mathematical assumption such as
+ * the intractability of factoring integers) is called a <em>cryptographically
+ * secure pseudorandom bit generator</em> (CSPRBG)."</li>
+ * </ul>
+ * <p>
+ * <b>IMPLEMENTATION NOTE</b>: 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, <b>DOES NOT</b> 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 <b>same block size</b> but without
+ * any knowledge of neither key material nor key size.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.cacr.math.uwaterloo.ca/hac">[HAC]</a>: Handbook of
+ * Applied Cryptography.<br>
+ * CRC Press, Inc. ISBN 0-8493-8523-7, 1997<br>
+ * Menezes, A., van Oorschot, P. and S. Vanstone.</li>
+ * </ol>
+ */
+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
+ * <code>offset</code>, for a maximum of <code>length</code> bytes with
+ * the output of this generator instance.
+ *
+ * @param out the placeholder to contain the generated random bytes.
+ * @param offset the starting index in <i>out</i> to consider. This method
+ * does nothing if this parameter is not within <code>0</code> and
+ * <code>out.length</code>.
+ * @param length the maximum number of required random bytes. This method does
+ * nothing if this parameter is less than <code>1</code>.
+ * @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.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * 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 <i>offset</i>, <i>length</i>, or
+ * <i>offset</i>+<i>length</i> 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 <code>seed</code>, 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
+ * <code>seed</code> 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 <i>Singleton</i> 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
+ * <i>Factory</i>.
+ *
+ * @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.
+ * <p>
+ * See <a href="http://www.ietf.org/rfc/rfc3280.txt">RFC 3280: Internet X.509
+ * Public Key Infrastructure Certificate and Certificate Revocation List (CRL)
+ * Profile</a>.
+ *
+ * @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.
+ * <p>
+ * The CRL is accepted iff:
+ * <ol>
+ * <li>The <i>nextUpdate</i> field (if present) is in the future.</li>
+ * <li>The CRL does not contain any unsupported critical extensions.</li>
+ * <li>The CRL is signed by one of the certificates in the path, or,</li>
+ * <li>The CRL is signed by the given public key and was issued by the public
+ * key's subject, or,</li>
+ * <li>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.</li>
+ * </ol>
+ *
+ * @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 <code>index</code>.
+ */
+ 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.security.provider package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.security.provider</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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
+ * <code>null</code>.
+ */
+ 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.
+ * <p>
+ * The Handbook of Applied Cryptography (HAC), by A. Menezes &amp; al. states:
+ * "Digital signature schemes which require the message as input to the
+ * verification algorithm are called <i>digital signature schemes with appendix</i>.
+ * ... They rely on cryptographic hash functions rather than customised
+ * redundancy functions, and are less prone to existential forgery attacks."
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.cacr.math.uwaterloo.ca/hac/">Handbook of Applied
+ * Cryptography</a>, Alfred J. Menezes, Paul C. van Oorschot and Scott A.
+ * Vanstone. Section 11.2.2 Digital signature schemes with appendix.</li>
+ * </ol>
+ */
+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 <code>buffer</code> of the first byte
+ * to consider.
+ * @param length the number of bytes in <code>buffer</code> starting from
+ * the byte at index <code>offset</code> 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 <code>sign()</code> method.
+ * @return <code>true</code> 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 <i>Raw</i> 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 <i>Factory</i> 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
+ * <code>/</code> and the canonical name of the encoding format.
+ * <p>
+ * 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 <code>null</code> 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 <code>null</code> 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 <code>null</code> 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
+ * <code>null</code> 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
+ * <code>null</code> 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 <code>null</code> 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 <i>Factory</i>.
+ *
+ * @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:
+ * <ol>
+ * <li>p: A prime modulus, where
+ * <code>2<sup>L-1</sup> &lt; p &lt; 2<sup>L</sup> </code> for <code>512 &lt;= L
+ * &lt;= 1024</code> and <code>L</code> a multiple of <code>64</code>.</li>
+ * <li>q: A prime divisor of <code>p - 1</code>, where <code>2<sup>159</sup>
+ * &lt; q &lt; 2<sup>160</sup></code>.</li>
+ * <li>g: Where <code>g = h<sup>(p-1)</sup>/q mod p</code>, where
+ * <code>h</code> is any integer with <code>1 &lt; h &lt; p - 1</code> such
+ * that <code>h<sup> (p-1)</sup>/q mod p > 1</code> (<code>g</code> has order
+ * <code>q mod p</code>).</li>
+ * <li>x: A randomly or pseudorandomly generated integer with <code>0 &lt; x
+ * &lt; q</code>.</li>
+ * <li>y: <code>y = g<sup>x</sup> mod p</code>.</li>
+ * <li>k: A randomly or pseudorandomly generated integer with <code>0 &lt; k
+ * &lt; q</code>.</li>
+ * </ol>
+ * <p>
+ * The integers <code>p</code>, <code>q</code>, and <code>g</code> can be
+ * public and can be common to a group of users. A user's private and public
+ * keys are <code>x</code> and <code>y</code>, respectively. They are
+ * normally fixed for a period of time. Parameters <code>x</code> and
+ * <code>k</code> are used for signature generation only, and must be kept
+ * secret. Parameter <code>k</code> must be regenerated for each signature.
+ * <p>
+ * The signature of a message <code>M</code> is the pair of numbers
+ * <code>r</code> and <code>s</code> computed according to the equations below:
+ * <ul>
+ * <li><code>r = (g<sup>k</sup> mod p) mod q</code> and</li>
+ * <li><code>s = (k<sup>-1</sup>(SHA(M) + xr)) mod q</code>.</li>
+ * </ul>
+ * <p>
+ * In the above, <code>k<sup>-1</sup></code> is the multiplicative inverse of
+ * <code>k</code>, <code>mod q</code>; i.e., <code>(k<sup>-1</sup> k) mod q =
+ * 1</code> and <code>0 &lt; k-1 &lt; q</code>. The value of <code>SHA(M)</code>
+ * is a 160-bit string output by the Secure Hash Algorithm specified in FIPS
+ * 180. For use in computing <code>s</code>, this string must be converted to
+ * an integer.
+ * <p>
+ * As an option, one may wish to check if <code>r == 0</code> or <code>s == 0
+ * </code>.
+ * If either <code>r == 0</code> or <code>s == 0</code>, a new value of
+ * <code>k</code> should be generated and the signature should be recalculated
+ * (it is extremely unlikely that <code>r == 0</code> or <code>s == 0</code> if
+ * signatures are generated properly).
+ * <p>
+ * The signature is transmitted along with the message to the verifier.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.itl.nist.gov/fipspubs/fip186.htm">Digital Signature
+ * Standard (DSS)</a>, Federal Information Processing Standards Publication
+ * 186. National Institute of Standards and Technology.</li>
+ * </ol>
+ */
+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 <code>r</code> and
+ * <code>s</code>.
+ */
+ 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 <code>r</code> and <code>s</code>.
+ */
+ 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
+ * <i>Raw</i> 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 <i>Raw</i> format supported by this
+ * library.
+ * <p>
+ * The <i>Raw</i> format for a DSA signature, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_DSS_SIGNATURE},</li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the DSS parameter
+ * <code>r</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSS parameter <code>r</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DSS parameter
+ * <code>s</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DSS parameter <code>s</code>.
+ * </li>
+ * </ol>
+ *
+ * @param signature the signature to encode, consisting of the two DSS
+ * parameters <code>r</code> and <code>s</code> as a
+ * {@link BigInteger} array.
+ * @return the <i>Raw</i> 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.
+ * <p>
+ * Digital signatures when transmitted in an X.509 certificates are encoded
+ * in DER (Distinguished Encoding Rules) as a BIT STRING; i.e.
+ *
+ * <pre>
+ * Certificate ::= SEQUENCE {
+ * tbsCertificate TBSCertificate,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ * }
+ * </pre>
+ * <p>
+ * The output of the encoder, and the input of the decoder, of this codec are
+ * then the <i>raw</i> bytes of such a BIT STRING; i.e. not the DER-encoded
+ * form itself.
+ * <p>
+ * RFC-2459 states that, for the Digital Signature Standard (DSS), which
+ * generates two MPIs, commonly called <code>r</code> and <code>s</code>, as the
+ * result of digitally signing a message, these two numbers will be transferred
+ * as the following ASN.1 structure:
+ *
+ * <pre>
+ * Dss-Sig-Value ::= SEQUENCE {
+ * r INTEGER,
+ * s INTEGER
+ * }
+ * </pre>
+ * <p>
+ * Client code that needs to build a DER BIT STRING <b>MUST</b> construct such
+ * an ASN.1 value. The following is an example of how to do this:
+ * <p>
+ * <pre>
+ * ...
+ * 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));
+ * ...
+ * </pre>
+ */
+public class DSSSignatureX509Codec
+ implements ISignatureCodec
+{
+ // implicit 0-arguments constructor
+
+ public int getFormatID()
+ {
+ return Registry.X509_ENCODING_ID;
+ }
+
+ /**
+ * Encodes a DSS Signature output as the <i>signature</i> 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
+ * <code>r</code> and <code>s</code>.
+ * @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 <i>signature</i> 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, <code>r</code> and <code>s</code> in this
+ * order, decoded from the designated <code>input</code>.
+ * @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.
+ * <p>
+ * EME-PKCS1-V1.5 is parameterised by the entity <code>k</code> which is the
+ * byte count of an RSA public shared modulus.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
+ * Standards (PKCS) #1:</a><br>
+ * RSA Cryptography Specifications Version 2.1.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ */
+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 <code>PS</code> of length <code>k - mLen -
+ * 3</code> consisting of pseudo-randomly generated nonzero octets. The length
+ * of <code>PS</code> will be at least eight octets.
+ * <p>
+ * The method then concatenates <code>PS</code>, the message <code>M</code>,
+ * and other padding to form an encoded message <code>EM</code> of length
+ * <code>k</code> octets as:
+ * <pre>
+ * EM = 0x00 || 0x02 || PS || 0x00 || M.
+ * </pre>
+ * <p>
+ * This method uses a default PRNG to obtain the padding bytes.
+ *
+ * @param M the message to encode.
+ * @return the encoded message <code>EM</code>.
+ */
+ 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 <code>EM</code>.
+ */
+ 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 <code>EM</code>.
+ */
+ 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 <code>EM</code> into an octet string
+ * <code>PS</code> consisting of nonzero octets and a message <code>M</code>
+ * as:
+ * <pre>
+ * EM = 0x00 || 0x02 || PS || 0x00 || M.
+ * </pre>
+ * <p>
+ * If the first octet of <code>EM</code> does not have hexadecimal value
+ * <code>0x00</code>, if the second octet of <code>EM</code> does not
+ * have hexadecimal value <code>0x02</code>, if there is no octet with
+ * hexadecimal value <code>0x00</code> to separate <code>PS</code> from
+ * <code>M</code>, or if the length of <code>PS</code> is less than
+ * <code>8</code> octets, output "decryption error" and stop.
+ *
+ * @param EM the designated encoded message.
+ * @return the decoded message <code>M</code> framed in the designated
+ * <code>EM</code> value.
+ * @throws IllegalArgumentException if the length of the designated entity
+ * <code>EM</code> is different than <code>k</code> (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.
+ * <p>
+ * 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
+ * Standards (PKCS) #1:</a><br>
+ * RSA Cryptography Specifications Version 2.1.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ */
+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 <i>M</i>.
+ * @param emLen intended length in octets of the encoded message, at least
+ * <code>tLen + 11</code>, where <code>tLen</code> is the octet length of the
+ * DER encoding <code>T</code> of a certain value computed during the
+ * encoding operation.
+ * @return encoded message, an octet string of length <code>emLen</code>.
+ * @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.
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
+ * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
+ * Primitive specification and supporting documentation.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ */
+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
+ * <code>M</code> using a hash function and maps the result to an encoded
+ * message <code>EM</code> 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 <i>M</i>.
+ * @param emBits the maximal bit length of the integer OS2IP(EM), at least
+ * <code>8.hLen + 8.sLen + 9</code>.
+ * @param salt the salt to use when encoding the output.
+ * @return the encoded message <code>EM</code>, an octet string of length
+ * <code>emLen = CEILING(emBits / 8)</code>.
+ * @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 <code>EM</code> and compares it to the hash of
+ * <code>M</code>.
+ *
+ * @param mHash the byte sequence resulting from applying the message digest
+ * algorithm Hash to the message <i>M</i>.
+ * @param EM the <i>encoded message</i>, an octet string of length
+ * <code>emLen = CEILING(emBits/8).
+ * @param emBits the maximal bit length of the integer OS2IP(EM), at least
+ * <code>8.hLen + 8.sLen + 9</code>.
+ * @param sLen the length, in octets, of the expected salt.
+ * @return <code>true</code> if the result of the verification was
+ * <i>consistent</i> with the expected reseult; and <code>false</code> if the
+ * result was <i>inconsistent</i>.
+ * @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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
+ * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
+ * Primitive specification and supporting documentation.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
+ * Standards (PKCS) #1:</a><br>
+ * RSA Cryptography Specifications Version 2.1.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * <li><a href="http://crypto.stanford.edu/~dabo/abstracts/ssl-timing.html">
+ * Remote timing attacks are practical</a><br>
+ * D. Boneh and D. Brumley.</li>
+ * </ol>
+ */
+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 <b>RSASP</b> method: Assuming that the designated
+ * RSA private key is a valid one, this method computes a <i>signature
+ * representative</i> for a designated <i>message representative</i> signed
+ * by the holder of the designated RSA private key.
+ *
+ * @param K the RSA private key.
+ * @param m the <i>message representative</i>: an integer between
+ * <code>0</code> and <code>n - 1</code>, where <code>n</code>
+ * is the RSA <i>modulus</i>.
+ * @return the <i>signature representative</i>, an integer between
+ * <code>0</code> and <code>n - 1</code>, where <code>n</code>
+ * is the RSA <i>modulus</i>.
+ * @throws ClassCastException if <code>K</code> is not an RSA one.
+ * @throws IllegalArgumentException if <code>m</code> (the <i>message
+ * representative</i>) 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 <b>RSAVP</b> method: Assuming that the designated
+ * RSA public key is a valid one, this method computes a <i>message
+ * representative</i> for the designated <i>signature representative</i>
+ * 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 <i>signature representative</i>, an integer between
+ * <code>0</code> and <code>n - 1</code>, where <code>n</code>
+ * is the RSA <i>modulus</i>.
+ * @return a <i>message representative</i>: an integer between <code>0</code>
+ * and <code>n - 1</code>, where <code>n</code> is the RSA
+ * <i>modulus</i>.
+ * @throws ClassCastException if <code>K</code> is not an RSA one.
+ * @throws IllegalArgumentException if <code>s</code> (the <i>signature
+ * representative</i>) 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 <code>RSAEP</code> algorithm.
+ *
+ * @param K the recipient's RSA public key.
+ * @param m the message representative as an MPI.
+ * @return the resulting MPI --an MPI between <code>0</code> and
+ * <code>n - 1</code> (<code>n</code> being the public shared
+ * modulus)-- that will eventually be padded with an appropriate
+ * framing/padding scheme.
+ * @throws ClassCastException if <code>K</code> is not an RSA one.
+ * @throws IllegalArgumentException if <code>m</code>, the message
+ * representative is not between <code>0</code> and
+ * <code>n - 1</code> (<code>n</code> 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 <code>RSADP</code> algorithm.
+ *
+ * @param K the recipient's RSA private key.
+ * @param c the ciphertext representative as an MPI.
+ * @return the message representative, an MPI between <code>0</code> and
+ * <code>n - 1</code> (<code>n</code> being the shared public
+ * modulus).
+ * @throws ClassCastException if <code>K</code> is not an RSA one.
+ * @throws IllegalArgumentException if <code>c</code>, the ciphertext
+ * representative is not between <code>0</code> and
+ * <code>n - 1</code> (<code>n</code> 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 <i>multi-precision integer</i> (MPI) <code>s</code> into an
+ * octet sequence of length <code>k</code>.
+ *
+ * @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 <code>s</code> is greater than <code>k</code>.
+ */
+ 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 <code>8b</code>,
+ * where <code>b</code> is in the range <code>[32..64]</code>.
+ *
+ * @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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
+ * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
+ * Primitive specification and supporting documentation.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
+ * Standards (PKCS) #1:</a><br>
+ * RSA Cryptography Specifications Version 2.1.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ */
+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
+ * <i>Raw</i> 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 <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for such a signature, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <p>
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE},
+ * <li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the RSA-PKCS#1 (v1.5)
+ * signature bytes in internet order,</li>
+ * <li>the RSA-PKCS#1 (v1.5) signature bytes in internet order.</li>
+ * </ol>
+ *
+ * @param signature the signature to encode, consisting of the output of the
+ * <code>sign()</code> method of a {@link RSAPKCS1V1_5Signature}
+ * instance --a byte array.
+ * @return the <i>Raw</i> 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 <i>magic</i> characters, or if the <i>version</i>
+ * 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.
+ * <p>
+ * Digital signatures when transmitted in an X.509 certificates are encoded
+ * in DER (Distinguished Encoding Rules) as a BIT STRING; i.e.
+ *
+ * <pre>
+ * Certificate ::= SEQUENCE {
+ * tbsCertificate TBSCertificate,
+ * signatureAlgorithm AlgorithmIdentifier,
+ * signature BIT STRING
+ * }
+ * </pre>
+ * <p>
+ * The output of the encoder, and the input of the decoder, of this codec are
+ * then the <i>raw</i> bytes of such a BIT STRING; i.e. not the DER-encoded
+ * form itself.
+ * <p>
+ * 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.
+ * <p>
+ * Client code that needs to build a DER BIT STRING <b>MUST</b> construct such
+ * an ASN.1 value. The following is an example of how to do this:
+ * <p>
+ * <pre>
+ * ...
+ * 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));
+ * ...
+ * </pre>
+ */
+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 <i>signature</i> 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 <i>signature</i> 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 <code>input</code> 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.
+ * <p>
+ * 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.cosic.esat.kuleuven.ac.be/nessie/workshop/submissions/rsa-pss.zip">
+ * RSA-PSS Signature Scheme with Appendix, part B.</a><br>
+ * Primitive specification and supporting documentation.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ */
+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 <i>salt</i>.
+ */
+ 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 <i>salt</i>.
+ *
+ * @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
+ * <i>Raw</i> 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 <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for an RSA-PSS signature, in this implementation, is
+ * a byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_RSA_PSS_SIGNATURE},
+ * <li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the RSA-PSS signature
+ * bytes in internet order,</li>
+ * <li>the RSA-PSS signature bytes in internet order.</li>
+ * </ol>
+ *
+ * @param signature the signature to encode, consisting of the output of the
+ * <code>sign()</code> method of a {@link RSAPSSSignature} instance
+ * --a byte array.
+ * @return the <i>Raw</i> 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 <code>rsa-</code>, followed by either
+ * <code>pss</code> or <code>pkcs1_v1.5</code>. An optional message digest
+ * name, to be used with the RSA signature may be specified by appending the
+ * hyphen chanaracter <code>-</code> 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 <code>null</code> 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 <i>RSA</i> signatures supported by this
+ * <i>Factory</i>.
+ *
+ * @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.
+ * <p>
+ * 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 <code>destroy()</code>.
+ * <p>
+ * 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 <i>delay</i> is negative, or if
+ * <code>delay + System.currentTimeMillis()</code> 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
+ * <code>null</code> 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 <code>null</code>
+ * 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 <code>0</code>
+ * 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.
+ * <p>
+ * 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 <code>valueOf(int)</code> method found in {@link Integer} of
+ * the RI's version 1.5 using a local LRU cache of 100 elements, organized by
+ * access order.
+ * <p>
+ * 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 <code>buffer</code> 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 <code>buffer</code> are
+ * replaced with pseudo-random data, iff the <code>buffer</code>
+ * size is not zero.
+ */
+ public void nextBytes(byte[] buffer)
+ {
+ nextBytes(buffer, 0, buffer.length);
+ }
+
+ /**
+ * Fills the designated <code>buffer</code>, starting from byte at position
+ * <code>offset</code> with, at most, <code>length</code> 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 2<sup>32</sup>.
+ */
+public final class Sequence
+ extends AbstractList
+{
+ private final Integer[] sequence;
+
+ /**
+ * Create a sequence of integers from 0 to <i>end</i>, with an increment of
+ * 1. If <i>end</i> 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 <i>start</i> to <i>end</i>, with an
+ * increment of 1. If <i>end</i> is less than <i>start</i>, 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 <i>start</i> to <i>end</i>, with an
+ * increment of <i>span</i>. If <i>end</i> is less than <i>start</i>, 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.
+ * <p>
+ * <i>span</i> can be negative, resulting in a decresing sequence.
+ * <p>
+ * If <i>span</i> is 0, then the sequence will contain {<i>start</i>,
+ * <i>end</i>} if <i>start</i> != <i>end</i>, or just the singleton
+ * <i>start</i> if <i>start</i> == <i>end</i>.
+ *
+ * @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.
+ * <p>
+ * This method calls the method with same name and three arguments as:
+ * <pre>
+ * toString(ba, 0, ba.length);
+ * </pre>
+ *
+ * @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
+ * <code>offset</code> and consisting of <code>length</code> 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.
+ * <p>
+ * This method calls the method with same name and three arguments as:
+ * <pre>
+ * toReversedString(ba, 0, ba.length);
+ * </pre>
+ *
+ * @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
+ * <code>offset</code> and consisting of <code>length</code> bytes. Each
+ * byte is converted to 2 hex symbols; zero(es) included.
+ * <p>
+ * 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);
+ }
+
+ /**
+ * <p>
+ * Returns a byte array from a string of hexadecimal digits.
+ * </p>
+ *
+ * @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 <code>0</code> to <code>15</code> 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 <code>n</code>.
+ *
+ * @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 <code>n</code>.
+ *
+ * @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 <code>toString()</code> 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 <code>toString()</code> 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 <code>toString()</code> 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 <code>m</code> is prepended to the start of each
+ * line.
+ * <p>
+ * If <code>offset</code> and <code>length</code> are omitted, the whole
+ * array is used. If <code>m</code> is omitted, nothing is prepended to each
+ * line.
+ *
+ * @param data the byte array to be dumped.
+ * @param offset the offset within <i>data</i> 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 <code>n</code>.
+ *
+ * @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).
+ * <p>
+ * 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.
+ * <p>
+ * 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 <code>str</code>.
+ * @throws NumberFormatException if <code>str</code> is <code>null</code>,
+ * or <code>str</code> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.security.util package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.security.util</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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
+ *
+ * <p><pre>OFFSET SIXTEEN-BYTES-IN-HEX PRINTABLE-BYTES</pre>
+ *
+ * <p>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<OID, Extension> 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<OID, Extension>();
+ 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<OID, Extension>();
+ }
+
+ // 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<String> getExtendedKeyUsage() throws CertificateParsingException
+ {
+ Extension e = getExtension(ExtendedKeyUsage.ID);
+ if (e != null)
+ {
+ List<OID> a = ((ExtendedKeyUsage) e.getValue()).getPurposeIds();
+ List<String> b = new ArrayList<String>(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<List<?>> getSubjectAlternativeNames()
+ throws CertificateParsingException
+ {
+ Extension e = getExtension(SubjectAlternativeNames.ID);
+ if (e != null)
+ {
+ List<GeneralName> names
+ = ((SubjectAlternativeNames) e.getValue()).getNames();
+ List<List<?>> list = new ArrayList<List<?>>(names.size());
+ for (GeneralName name : names)
+ {
+ List<Object> n = new ArrayList<Object>(2);
+ n.add(name.kind().tag());
+ n.add(name.name());
+ list.add(n);
+ }
+ return list;
+ }
+ return null;
+ }
+
+ public Collection<List<?>> getIssuerAlternativeNames()
+ throws CertificateParsingException
+ {
+ Extension e = getExtension(IssuerAlternativeNames.ID);
+ if (e != null)
+ {
+ List<GeneralName> names
+ = ((IssuerAlternativeNames) e.getValue()).getNames();
+ List<List<?>> list = new ArrayList<List<?>>(names.size());
+ for (GeneralName name : names)
+ {
+ List<Object> n = new ArrayList<Object>(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<String> getCriticalExtensionOIDs()
+ {
+ HashSet<String> s = new HashSet<String>();
+ for (Extension e : extensions.values())
+ {
+ if (e.isCritical())
+ s.add(e.getOid().toString());
+ }
+ return Collections.unmodifiableSet(s);
+ }
+
+ public Set<String> getNonCriticalExtensionOIDs()
+ {
+ HashSet<String> s = new HashSet<String>();
+ 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<OID> policies;
+ private final Map<OID, List<PolicyQualifierInfo>> 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<OID> policyList = new LinkedList<OID>();
+ HashMap<OID, List<PolicyQualifierInfo>> qualifierMap
+ = new HashMap<OID, List<PolicyQualifierInfo>>();
+ 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<PolicyQualifierInfo> quals = new LinkedList<PolicyQualifierInfo>();
+ 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<OID> policies,
+ final Map<OID, List<PolicyQualifierInfo>> 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<OID>(policies));
+ this.policyQualifierInfos = Collections.unmodifiableMap
+ (new HashMap<OID, List<PolicyQualifierInfo>>(policyQualifierInfos));
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public List<OID> getPolicies()
+ {
+ return policies;
+ }
+
+ /**
+ * Returns the list of policy OIDs, formatted as dotted-decimal strings.
+ *
+ * @return
+ */
+ public List<String> getPolicyStrings()
+ {
+ List<String> l = new ArrayList<String>(policies.size());
+ for (OID oid : policies)
+ {
+ l.add(oid.toString());
+ }
+ return l;
+ }
+
+ public List<PolicyQualifierInfo> getPolicyQualifierInfos(OID oid)
+ {
+ return policyQualifierInfos.get(oid);
+ }
+
+ public byte[] getEncoded()
+ {
+ if (encoded == null)
+ {
+ List<DERValue> pol = new ArrayList<DERValue>(policies.size());
+ for (Iterator<OID> it = policies.iterator(); it.hasNext(); )
+ {
+ OID policy = it.next();
+ List<PolicyQualifierInfo> qualifiers = getPolicyQualifierInfos(policy);
+ List<DERValue> l = new ArrayList<DERValue>(qualifiers == null ? 1 : 2);
+ l.add(new DERValue(DER.OBJECT_IDENTIFIER, policy));
+ if (qualifiers != null)
+ {
+ List<DERValue> ll = new ArrayList<DERValue>(qualifiers.size());
+ for (Iterator<PolicyQualifierInfo> 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<OID> 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<OID>();
+ 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<OID> 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<DERValue> ext = new ArrayList<DERValue>(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.
+ *
+ * <pre>
+ 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 }
+</pre>
+ *
+ * @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<GeneralName> names;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ public GeneralNames(final byte[] encoded) throws IOException
+ {
+ names = new LinkedList<GeneralName>();
+ 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<GeneralName> 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.
+ *
+ * <pre>
+ GeneralSubtree ::= SEQUENCE {
+ base GeneralName,
+ minimum [0] BaseDistance DEFAULT 0,
+ maximum [1] BaseDistance OPTIONAL }
+
+ BaseDistance ::= INTEGER (0..MAX)</pre>
+ *
+ * @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<GeneralName> 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:
+ *
+ * <pre>
+ 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)
+ </pre>
+ *
+ * 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<GeneralSubtree> permittedSubtrees;
+ private List<GeneralSubtree> 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<GeneralSubtree>();
+ excludedSubtrees = new LinkedList<GeneralSubtree>();
+ 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<GeneralSubtree> permittedSubtrees()
+ {
+ return Collections.unmodifiableList(permittedSubtrees);
+ }
+
+ public List<GeneralSubtree> 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<GeneralName> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.security.x509.ext package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.security.x509.ext</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.security.x509 package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.security.x509</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 <guilhem@kaffe.org>
+ * @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 <tromey@cygnus.com>
+ * @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 <code>pos</code>.
+ * 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 <tromey@cygnus.com>
+ * @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 <guilhem@kaffe.org>
+ * @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 <guilhem@kaffe.org>
+ * @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 <code>s</code>, a set of ranges
+ * and the corresponding attributes. This is used to build an iterator.
+ * The array <code>ranges</code> should be formatted as follow:
+ * each element of <code>ranges</code> specifies the index in the string
+ * until which the corresponding map of attributes at the same position
+ * is applied. For example, if you have:
+ * <pre>
+ * s = "hello";
+ * ranges = new int[] { 2, 6 };
+ * attributes = new HashMap[2];
+ * </pre>
+ * <code>"he"</code> will have the attributes <code>attributes[0]</code>,
+ * <code>"llo"</code> the <code>attributes[1]</code>.
+ */
+ 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<attributes.length;i++)
+ if (attributes[i] != null)
+ return ranges[i-1];
+ return formattedString.length();
+ }
+
+ return getRunLimit (attributes[attributeIndex].keySet());
+ }
+
+ public int getRunStart (Set reqAttrs)
+ {
+ if (attributes == null)
+ return formattedString.length();
+
+ int currentAttrIndex = attributeIndex;
+ Set newKeys = null;
+
+ do
+ {
+ if (currentAttrIndex == 0)
+ return 0;
+
+ currentAttrIndex--;
+ if (attributes[currentAttrIndex] == null)
+ break;
+ newKeys = attributes[currentAttrIndex].keySet();
+ }
+ while (newKeys.containsAll (reqAttrs));
+
+ return (currentAttrIndex > 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<attributes.length;
+ attributeIndex++)
+ if (ranges[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 (;i<this.ranges.length;i++)
+ {
+ new_attributes.add (this.attributes[i]);
+ new_ranges.add (new Integer (this.ranges[i]));
+ }
+ }
+ if (j != ranges.length)
+ {
+ for (;j<ranges.length;j++)
+ {
+ new_attributes.add (attributes[j]);
+ new_ranges.add (new Integer (ranges[j]));
+ }
+ }
+
+ this.attributes = new HashMap[new_attributes.size()];
+ this.ranges = new int[new_ranges.size()];
+ System.arraycopy (new_attributes.toArray(), 0, this.attributes,
+ 0, this.attributes.length);
+
+ for (i=0;i<new_ranges.size();i++)
+ {
+ this.ranges[i] = ((Integer)new_ranges.elementAt (i)).intValue();
+ }
+
+ dumpTable();
+ }
+
+ /**
+ * This method appends to the internal attributed string the attributed
+ * string contained in the specified iterator.
+ *
+ * @param iterator the iterator which contains the attributed string to
+ * append to this iterator.
+ */
+ public void append (AttributedCharacterIterator iterator)
+ {
+ char c = iterator.first();
+ Vector more_ranges = new Vector();
+ Vector more_attributes = new Vector();
+
+ do
+ {
+ formattedString = formattedString + String.valueOf (c);
+ // TODO: Reduce the size of the output array.
+ more_attributes.add (iterator.getAttributes());
+ more_ranges.add (new Integer (formattedString.length()));
+ // END TOOD
+ c = iterator.next();
+ }
+ while (c != DONE);
+
+ HashMap[] new_attributes = new HashMap[attributes.length
+ + more_attributes.size()];
+ int[] new_ranges = new int[ranges.length + more_ranges.size()];
+
+ System.arraycopy (attributes, 0, new_attributes, 0, attributes.length);
+ System.arraycopy (more_attributes.toArray(), 0, new_attributes,
+ attributes.length, more_attributes.size());
+
+ System.arraycopy (ranges, 0, new_ranges, 0, ranges.length);
+ Object[] new_ranges_array = more_ranges.toArray();
+ for (int i = 0; i < more_ranges.size();i++)
+ new_ranges[i+ranges.length] = ((Integer) new_ranges_array[i]).intValue();
+
+ attributes = new_attributes;
+ ranges = new_ranges;
+ }
+
+ /**
+ * This method appends an attributed string which attributes are specified
+ * directly in the calling parameters.
+ *
+ * @param text The string to append.
+ * @param local_attributes The attributes to put on this string in the
+ * iterator. If it is <code>null</code> 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 <code>null</code>.
+ *
+ * @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 <tromey@cygnus.com>
+ * @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 <tromey@cygnus.com>
+ * @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 <guilhem@kaffe.org>
+ * @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 <tromey@cygnus.com>
+ * @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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.text package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.text</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 <tt>buf</tt> 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 <tt>buf</tt> 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 <tt>buf</tt> 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.<br>
+ *
+ * In the default case:
+ * <pre>
+ * doubleEnum = new DoubleEnumeration(enum1, enum2);
+ * while (doubleEnum.hasMoreElements()) {
+ * Object o = doubleEnum.nextElement();
+ * do_something(o);
+ * }
+ * </pre>
+ * 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<T> implements Enumeration<T>
+{
+ /**
+ * This is true as long as one of the enumerations has more
+ * elements.
+ * Only valid when hasChecked is true.
+ * Set in <code>hasMoreElements()</code>
+ */
+ private boolean hasMore;
+ /**
+ * This is true, if it is sure that hasMore indicates wether there are
+ * more elements.
+ * Set to true in <code>hasMoreElements()</code>.
+ * Set to false in <code>getNextElement()</code>.
+ */
+ private boolean hasChecked;
+ /**
+ * The first enumeration.
+ */
+ private Enumeration<T> e1;
+ /**
+ * The second enumeration.
+ */
+ private Enumeration<T> e2;
+
+ /**
+ * Creates a new Enumeration combining the given two enumerations.
+ * The enumerations mustn't be accessed by other classes.
+ */
+ public DoubleEnumeration(Enumeration<T> e1, Enumeration<T> 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 <code>NoSuchElementException</code>.
+ */
+ 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. <code>getInstance()</code> 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<T> implements Enumeration<T>, Serializable
+{
+ /** The only instance of this class */
+ private static final EmptyEnumeration<Object> instance =
+ new EmptyEnumeration<Object>();
+
+ /**
+ * 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<Object> getInstance()
+ {
+ return instance;
+ }
+
+ /**
+ * Returns false, since there are no elements.
+ *
+ * @return false
+ */
+ public boolean hasMoreElements()
+ {
+ return false;
+ }
+
+ /**
+ * Always throws <code>NoSuchElementException</code>, 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<K,V>
+ extends LinkedHashMap<K,V>
+{
+
+ /**
+ * 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 <code>true</code> when the oldest entry should be removed.
+ *
+ * @param eldest the entry about to be removed
+ *
+ * @return <code>true</code> when the oldest entry should be removed
+ */
+ protected boolean removeEldestEntry(Map.Entry<K, V> 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.
+ *
+ * <p>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 <code>entrySet</code>
+ * has similar phenomenons: The size may spontaneously shrink, or an
+ * entry, that was in the set before, suddenly disappears.
+ *
+ * <p>A weak hash map is not meant for caches; use a normal map, with
+ * soft references as values instead, or try {@link LinkedHashMap}.
+ *
+ * <p>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.
+ *
+ * <p>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 <i>null</i>. 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 <code>rehash()</code>.
+ */
+ 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
+ * <code>next()</code> call. This is also the entry whose
+ * bucket should be removed by the <code>remove</code> call. <br>
+ *
+ * It is null, if the <code>next</code> method wasn't
+ * called yet, or if the entry was already removed. <br>
+ *
+ * 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
+ * <code>next()</code> call. It is <code>null</code> if there
+ * is no further entry. <br>
+ *
+ * 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 <code>next()</code> 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. <br>
+ *
+ * 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
+ * <code>Math.abs(key.hashCode() % buckets.length)</code>.
+ *
+ * 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 <code>Entry</code> 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 <code>entrySet()</code>.
+ */
+ 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. <br>
+ *
+ * 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
+ * <code>add()</code> 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 <code>ZoneInfo</code> 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
+ * (<offset, isdst, zonename>) 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 <i>Manifest</i> and
+ * <i>Manifest-like</i> files.
+ * <p>
+ * JAR-related files that resemble <i>Manifest</i> files are Signature files
+ * (with an <code>.SF</code> 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 <code>Mainfest</code> attributes. This
+ * implementation respects the rule stated in the Jar Specification concerning
+ * the maximum allowed line length; i.e.
+ *
+ * <pre>
+ * 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).
+ * </pre>
+ *
+ * and
+ *
+ * <pre>
+ * 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).
+ * </pre>
+ *
+ * @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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.util package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.util</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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 <neugens@limasoftware.net>
+ */
+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
+ * <code>"/system"</code> directory of GConf for the current user, while User
+ * Root is <code>"/apps/java"</code>. These defaults can be modified by
+ * defining two system properties:<br />
+ * <br />
+ * User Root:<br />
+ * <br />
+ *
+ * <pre>
+ * gnu.java.util.prefs.gconf.user_root
+ * </pre>
+ *
+ * <br />
+ * <br />
+ * and System Root:<br />
+ * <br />
+ *
+ * <pre>
+ * gnu.java.util.prefs.gconf.system_root
+ * </pre>
+ *
+ * <br />
+ *
+ * @author Mario Torre <neugens@limasoftware.net>
+ */
+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 <code>isUser</code> 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 <code>isUser</code> 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 <code>true</code> initializes this node to be
+ * a user node, <code>false</code> 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 <code>size</code> 0 (that is, not <code>null</code>).
+ *
+ * @return A <code>String</code> array of names of children of the current
+ * node.
+ * @throws BackingStoreException if this operation cannot be completed.
+ */
+ protected String[] childrenNamesSpi() throws BackingStoreException
+ {
+ List<String> 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 <code>String</code> array of keys stored under the current
+ * node.
+ * @throws BackingStoreException if this operation cannot be completed.
+ */
+ protected String[] keysSpi() throws BackingStoreException
+ {
+ List<String> 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<String> 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<String> 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, <code>null</code> 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 <code>true</code> if this preference node is a user node,
+ * <code>false</code> if is a system preference node.
+ *
+ * @return <code>true</code> if this preference node is a user node,
+ * <code>false</code> 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 (<code>true</code>) or system
+ * (<code>false</code>) 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<String, String> entries = new HashMap<String, String>();
+
+ /**
+ * 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 <code>newNode</code> 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 <code>isUser</code> 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("<preferences");
+
+ readRoot();
+
+ // Ending tag
+ skipTill("</preferences>");
+ }
+
+ private void readRoot()
+ throws InvalidPreferencesFormatException, IOException
+ {
+ // Begin starting tag
+ skipTill("<root");
+
+ // type attribute
+ skipTill("type=\"");
+ String type = readTill("\"");
+ Preferences root;
+ if ("user".equals(type)) {
+ root = factory.userRoot();
+ } else if ("system".equals(type)) {
+ root = factory.systemRoot();
+ } else {
+ throw new InvalidPreferencesFormatException("Unknown type: "
+ + type);
+ }
+
+ // Read root map and subnodes
+ readMap(root);
+ readNodes(root);
+
+ // Ending tag
+ skipTill("</root>");
+ }
+
+ private void readNodes(Preferences node)
+ throws InvalidPreferencesFormatException, IOException
+ {
+ while ("node".equals(nextTag())) {
+ skipTill("<node");
+ skipTill("name=\"");
+ String name = readTill("\"");
+ Preferences subnode = node.node(name);
+ readMap(subnode);
+ readNodes(subnode);
+ skipTill("</node>");
+ }
+
+ }
+
+ private void readMap(Preferences node)
+ throws InvalidPreferencesFormatException, IOException
+ {
+ // Begin map tag
+ skipTill("<map");
+
+ // Empty map?
+ if (line.startsWith("/>")) {
+ line = line.substring(2);
+ return;
+ }
+
+ // Map entries
+ readEntries(node);
+
+ // Ending tag
+ skipTill("</map>");
+ }
+
+ private void readEntries(Preferences node)
+ throws InvalidPreferencesFormatException, IOException
+ {
+ while ("entry".equals(nextTag())) {
+ skipTill("<entry");
+ skipTill("key=\"");
+ String key = readTill("\"");
+ skipTill("value=\"");
+ String value = readTill("\"");
+ node.put(key, value);
+ }
+ }
+
+ private void skipTill(String s)
+ throws InvalidPreferencesFormatException, IOException
+ {
+ while(true) {
+ if (line == null)
+ throw new InvalidPreferencesFormatException(s + " not found");
+
+ int index = line.indexOf(s);
+ if (index == -1) {
+ line = br.readLine();
+ } else {
+ line = line.substring(index+s.length());
+ return;
+ }
+ }
+ }
+
+ private String readTill(String s)
+ throws InvalidPreferencesFormatException
+ {
+ int index = line.indexOf(s);
+ if (index == -1)
+ throw new InvalidPreferencesFormatException(s + " not found");
+
+ String read = line.substring(0, index);
+ line = line.substring(index+s.length());
+
+ return read;
+ }
+
+ private String nextTag()
+ throws InvalidPreferencesFormatException, IOException
+ {
+ while(true) {
+ if (line == null)
+ throw new InvalidPreferencesFormatException("unexpected EOF");
+
+ int start = line.indexOf("<");
+ if (start == -1) {
+ line = br.readLine();
+ } else {
+ // Find end of tag
+ int end = start+1;
+ while (end != line.length()
+ && " \t\r\n".indexOf(line.charAt(end)) == -1) {
+ end++;
+ }
+ // Line now starts at the found tag
+ String tag = line.substring(start+1,end);
+ line = line.substring(start);
+ return tag;
+ }
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/java/util/prefs/NodeWriter.java b/libjava/classpath/gnu/java/util/prefs/NodeWriter.java
new file mode 100644
index 000000000..3e4f972ed
--- /dev/null
+++ b/libjava/classpath/gnu/java/util/prefs/NodeWriter.java
@@ -0,0 +1,319 @@
+/* NodeWriter - Writes and exports preferences nodes to files
+ 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 gnu.java.lang.CPStringBuilder;
+
+import java.io.BufferedWriter;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+
+import java.util.StringTokenizer;
+
+import java.util.prefs.*;
+
+/**
+ * Writes and exports preferences nodes to files
+ *
+ * @author Mark Wielaard (mark@klomp.org)
+ */
+public class NodeWriter {
+
+ /** The Preferences node to write. */
+ private final Preferences prefs;
+
+ /** The bufferedWriter to write the node to. */
+ private final BufferedWriter bw;
+
+ /**
+ * True if the complete sub tree should be written,
+ * false if only the node should be written.
+ */
+ private boolean subtree;
+
+ /**
+ * Creates a new NodeWriter for the given preferences node and
+ * outputstream. Creates a new OutputStreamWriter.
+ */
+ public NodeWriter(Preferences prefs, OutputStream os) {
+ this.prefs = prefs;
+ Writer w;
+ try
+ {
+ w = new OutputStreamWriter(os, "UTF-8");
+ }
+ catch (UnsupportedEncodingException uee)
+ {
+ // Shouldn't happen, since we always have UTF-8 available.
+ InternalError ie = new InternalError("UTF-8 encoding missing");
+ ie.initCause(uee);
+ throw ie;
+ }
+ this.bw = new BufferedWriter(w);
+ }
+
+ /**
+ * Writes the preference node plus the complete subtree.
+ */
+ public void writePrefsTree() throws BackingStoreException, IOException {
+ subtree = true;
+ writeHeader();
+ writePreferences();
+ bw.flush();
+ }
+
+ /**
+ * Writes only the preference node.
+ */
+ public void writePrefs() throws BackingStoreException, IOException {
+ subtree = false;
+ writeHeader();
+ writePreferences();
+ bw.flush();
+ }
+
+ /**
+ * Writes the standard header.
+ */
+ private void writeHeader() throws BackingStoreException, IOException {
+ bw.write("<?xml version=\"1.0\"?>");
+ bw.newLine();
+ bw.write("<!DOCTYPE preferences SYSTEM "
+ + "\"http://java.sun.com/dtd/preferences.dtd\">");
+ bw.newLine();
+ bw.newLine();
+ bw.write("<!-- GNU Classpath java.util.prefs Preferences ");
+
+ if (prefs.isUserNode()) {
+ bw.write("user");
+ } else {
+ bw.write("system");
+ }
+
+ // root node?
+ if (prefs.parent() == null) {
+ bw.write(" root");
+ }
+
+ if (subtree) {
+ bw.write(" tree");
+ } else {
+ bw.write(" node");
+ }
+
+ // no root?
+ if (prefs.parent() != null) {
+ bw.newLine();
+ bw.write(" '");
+ bw.write(prefs.absolutePath());
+ bw.write('\'');
+ bw.newLine();
+ }
+ bw.write(" -->");
+ bw.newLine();
+ bw.newLine();
+ }
+
+ /**
+ * Write the preferences tag and the root.
+ */
+ private void writePreferences() throws BackingStoreException, IOException {
+ bw.write("<preferences>");
+ bw.newLine();
+ writeRoot();
+ bw.write("</preferences>");
+ bw.newLine();
+ }
+
+ private void writeRoot() throws BackingStoreException, IOException {
+ bw.write(" <root type=\"");
+ if (prefs.isUserNode()) {
+ bw.write("user");
+ } else {
+ bw.write("system");
+ }
+ bw.write("\">");
+
+ writeRootMap();
+ writeNode();
+
+ bw.write(" </root>");
+ 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("<map/>");
+ 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 <code>writeCloseParents()</code> 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<parents; i++) {
+ String name = st.nextToken();
+ indent(i+2);
+ bw.write("<node name=\"" + name + "\">");
+ bw.write("<map/>");
+ bw.write("</node>");
+ bw.newLine();
+ }
+ } else {
+ parents = 0;
+ }
+
+ return parents;
+ }
+
+ private void writeCloseParents(int parents) throws IOException {
+ while(parents > 0) {
+ indent(parents+1);
+ bw.write("</node>");
+ 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("<node name=\"" + node.name() + "\">");
+ if (node.keys().length > 0) {
+ bw.newLine();
+ }
+ writeMap(node, indent+1);
+ }
+
+ if (subtree) {
+ String[] children = node.childrenNames();
+ for (int i=0; i<children.length; i++) {
+ Preferences child = node.node(children[i]);
+ writeNode(child, indent+1);
+ }
+ }
+
+ // not root?
+ if (node.parent() != null) {
+ indent(indent);
+ bw.write("</node>");
+ 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("<map>");
+ bw.newLine();
+ writeEntries(node, indentString + " ");
+ bw.write(indentString);
+ bw.write("</map>");
+ } else {
+ bw.write("<map/>");
+ }
+ 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("<entry key=\"" + keys[i] + "\""
+ + " value=\"" + value + "\"/>");
+ bw.newLine();
+ }
+ }
+
+ private void indent(int x) throws IOException {
+ for (int i=0; i<x; i++) {
+ bw.write(" ");
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java b/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java
new file mode 100644
index 000000000..64fc0498a
--- /dev/null
+++ b/libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java
@@ -0,0 +1,286 @@
+/* GConfNativePeer.java -- GConf based preference peer for native 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.util.prefs.gconf;
+
+import java.util.List;
+import java.util.prefs.BackingStoreException;
+
+/**
+ * Native peer for GConf based preference backend.
+ *
+ * @author Mario Torre <neugens@limasoftware.net>
+ */
+public final class GConfNativePeer
+{
+ /**
+ * Creates a new instance of GConfNativePeer
+ */
+ public GConfNativePeer()
+ {
+ init_class();
+ }
+
+ /**
+ * Queries whether the node <code>node</code> exists in theGConf database.
+ * Returns <code>true</code> or <code>false</code>.
+ *
+ * @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<String> getKeys(String node) throws BackingStoreException
+ {
+ return gconf_all_keys(node);
+ }
+
+ /**
+ * Lists the subnodes in <code>node</code>. 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<String> 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<String> 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<String> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in gnu.java.util.prefs package.
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the 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.java.util.prefs</title></head>
+
+<body>
+<p></p>
+
+</body>
+</html>
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</A>
+ */
+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 <A HREF="mailto:wes@cacas.org">Wes Biggs</A>
+ */
+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.
+ * <P>
+ * 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,
+ * <code>RESyntax.RE_SYNTAX_PERL5</code> is used).
+ * <P>
+ * 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.
+ * <P>
+ * Various methods attempt to match input text against a compiled
+ * regular expression. These methods are:
+ * <LI><code>isMatch</code>: returns true if the input text in its
+ * entirety matches the regular expression pattern.
+ * <LI><code>getMatch</code>: returns the first match found in the
+ * input text, or null if no match is found.
+ * <LI><code>getAllMatches</code>: returns an array of all
+ * non-overlapping matches found in the input text. If no matches are
+ * found, the array is zero-length.
+ * <LI><code>substitute</code>: substitute the first occurence of the
+ * pattern in the input text with a replacement string (which may
+ * include metacharacters $0-$9, see REMatch.substituteInto).
+ * <LI><code>substituteAll</code>: same as above, but repeat for each
+ * match before returning.
+ * <LI><code>getMatchEnumeration</code>: 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 <code>getAllMatches</code>.
+ * <P>
+ *
+ * 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.
+ *
+ * <P>
+ *
+ * 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.
+ *
+ * <P>
+ * You can optionally affect the execution environment by using a
+ * combination of execution flags (constants listed below).
+ *
+ * <P>
+ * All operations on a regular expression are performed in a
+ * thread-safe manner.
+ *
+ * @author <A HREF="mailto:wes@cacas.org">Wes Biggs</A>
+ * @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.
+ * <P>
+ * This example demonstrates the results of various ways of matching on
+ * a substring.
+ * <P>
+ * <CODE>
+ * String s = "food bar fool";<BR>
+ * RE exp = new RE("^foo.");<BR>
+ * REMatch m0 = exp.getMatch(s);<BR>
+ * REMatch m1 = exp.getMatch(s.substring(8));<BR>
+ * REMatch m2 = exp.getMatch(s.substring(8),0,RE.REG_NOTBOL); <BR>
+ * REMatch m3 = exp.getMatch(s,8); <BR>
+ * REMatch m4 = exp.getMatch(s,8,RE.REG_ANCHORINDEX); <BR>
+ * <P>
+ * // Results:<BR>
+ * // m0.toString(): "food"<BR>
+ * // m1.toString(): "fool"<BR>
+ * // m2.toString(): null<BR>
+ * // m3.toString(): null<BR>
+ * // m4.toString(): "fool"<BR>
+ * </CODE>
+ */
+ 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 \&lt;
+ * 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:
+ * <OL>
+ * <LI> A descriptive message of the error.
+ * <LI> An integral type code equivalent to one of the statically
+ * defined symbols listed below.
+ * <LI> The approximate position in the input string where the error
+ * occurred.
+ * </OL>
+ *
+ * @author <A HREF="mailto:wes@cacas.org">Wes Biggs</A>
+ */
+
+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. <B>Not implemented</B>.
+ */
+ 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. <B>Not implemented</B>.
+ */
+ public static final int REG_EEND = 9;
+
+ /**
+ * Error flag.
+ * Invalid escape sequence. <B>Not implemented</B>.
+ */
+ 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. <B>Not implemented</B>.
+ */
+ public static final int REG_ESIZE = 12;
+
+ /**
+ * Error flag.
+ * The regex routines ran out of memory. <B>Not implemented</B>.
+ */
+ 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 <A HREF="mailto:wes@cacas.org">Wes Biggs</A>
+ * @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 <A HREF="mailto:wes@cacas.org">Wes Biggs</A>
+ */
+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:
+ * <P>
+ * <code>
+ * REMatch myMatch = myExpression.getMatch(myString);<br>
+ * if (myMatch != null) System.out.println("Regexp found: "+myMatch);
+ * </code>
+ */
+ 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:
+ *
+ * <P>
+ * <code>REMatch myMatch = myExpression.getMatch(myString);</code>
+ * <P>
+ * can be viewed (given that myMatch is not null) by creating
+ * <P>
+ * <code>String theMatch = myString.substring(myMatch.getStartIndex(),
+ * myMatch.getEndIndex());</code>
+ * <P>
+ * But you can save yourself that work, since the <code>toString()</code>
+ * 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 <i>sub</i> begins, or <code>-1</code> 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 <i>sub</i> begins, or <code>-1</code> 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 <i>sub</i> ends, or <code>-1</code> 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 <i>sub</i> ends, or <code>-1</code> 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
+ * <code>$0</code> through <code>$9</code>. <code>$0</code> matches
+ * the full substring matched; <code>$<i>n</i></code> matches
+ * subexpression number <i>n</i>.
+ * <code>$10, $11, ...</code> may match the 10th, 11th, ... subexpressions
+ * if such subexpressions exist.
+ *
+ * @param input A string consisting of literals and <code>$<i>n</i></code> 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 <code>getMatchEnumeration()</code> methods on an instance of
+ * RE.
+ *
+ * <P>
+ *
+ * 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
+ * <code>getAllMatches()</code> methods on RE. However, using an
+ * enumeration can help speed performance when the entire text does
+ * not need to be searched immediately.
+ *
+ * <P>
+ *
+ * The enumerated type is especially useful when searching on a Reader
+ * or InputStream, because the InputStream read position cannot be
+ * guaranteed after calling <code>getMatch()</code> (see the
+ * description of that method for an explanation of why). Enumeration
+ * also saves a lot of overhead required when calling
+ * <code>getMatch()</code> multiple times.
+ *
+ * @author <A HREF="mailto:wes@cacas.org">Wes Biggs</A>
+ */
+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 <A HREF="mailto:wes@cacas.org">Wes Biggs</A>
+ */
+
+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.
+ * <B>Not implemented.</B>
+ */
+ public static final int RE_CONTEXT_INDEP_ANCHORS = 3;
+
+ /**
+ * Syntax bit. Repetition operators are only special in valid positions.
+ * <B>Not implemented.</B>
+ */
+ 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.
+ * <B>Not implemented</B>.
+ */
+ 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. <B>Not implemented</B>.
+ */
+ 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. <B>Not implemented.</B>
+ */
+ 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.
+ * <P>
+ * 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 <A HREF="mailto:wes@cacas.org">Wes Biggs</A>
+ * @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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ * @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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ * @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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ * @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 <code>Assembly</code> 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 <code>LoopbackTransformer</code>
+ * element.
+ * <p>
+ * Once constructed, and correctly initialised, the bulk of the methods
+ * available on the <code>Assembly</code> are delegated to the <i>head</i> of
+ * the {@link Transformer} chain of the <code>Assembly</code>.
+ *
+ * @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 <i>chain</i> to a
+ * <code>LoopbackTransformer</code>.
+ */
+ 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, <b>before</b> it passes that stream to
+ * the next element in the <i>chain</i>.
+ *
+ * @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, <b>after</b> it passes that stream to
+ * the next element in the <i>chain</i>.
+ *
+ * @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 <code>Assembly</code> 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 <code>Assembly</code> 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 <code>1</code> 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 <code>in</code>, starting from index position
+ * <code>0</code> 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 <code>in</code> 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 <code>1</code> 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 <code>in</code>, starting from index position
+ * <code>0</code> 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 <i>push</i> operation for this
+ * <code>Assembly</code>.
+ *
+ * @param in the input data bytes.
+ * @param offset index of <code>in</code> 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 <i>Cascade</i> 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 <code>i</code> is input to stage <code>i + 1</code>; and the
+ * output of the last stage is the <i>Cascade</i>'s ciphertext output.
+ * <p>
+ * In the simplest case, all stages in a <code>Cascade</code> have <i>k</i>-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).
+ * <p>
+ * 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 <i>Mode</i> of Operations.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.cacr.math.uwaterloo.ca/hac">[HAC]</a>: Handbook of
+ * Applied Cryptography.<br>
+ * CRC Press, Inc. ISBN 0-8493-8523-7, 1997<br>
+ * Menezes, A., van Oorschot, P. and S. Vanstone.</li>
+ * </ol>
+ */
+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 <code>abs(a)</code> and <code>abs(b)</code>.
+ */
+ 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 <code>index</code> is less than
+ * <code>0</code> 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
+ * <code>Cascade</code> 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 <i>plaintext</i> (if initialised in the
+ * {@link Direction#FORWARD} state) or <i>ciphertext</i> (if initialised in
+ * the {@link Direction#REVERSED} state).
+ *
+ * @param in the plaintext.
+ * @param inOffset index of <code>in</code> from which to start considering
+ * data.
+ * @param out the ciphertext.
+ * @param outOffset index of <code>out</code> 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 <i>correctness</i> 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 <code>true</code> if the implementation passes simple
+ * <i>correctness</i> tests. Returns <code>false</code> 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 <i>Stage</i> 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.
+ * <p>
+ * This {@link Transformer} uses a {@link Deflater} instance to carry on the
+ * compression, and an {@link Inflater} to do the decompression.
+ * <p>
+ * 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.
+ * <p>
+ * The possible values for this type are two:
+ * <ol>
+ * <li>FORWARD: equivalent to {@link gnu.javax.crypto.mode.IMode#ENCRYPTION},
+ * and its inverse value</li>
+ * <li>REVERSED: equivalent to {@link gnu.javax.crypto.mode.IMode#DECRYPTION}.
+ * </li>
+ * </ol>
+ */
+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.
+ * <p>
+ * 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}.
+ * <p>
+ * The possible values for this type are two:
+ * <ol>
+ * <li>PRE_PROCESSING: where the input data is first processed by the current
+ * {@link Transformer} before being passed to the rest of the chain; and</li>
+ * <li>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}.</li>
+ * </ol>
+ */
+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}.
+ * <p>
+ * 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 <i>Stage</i> in a Cascade Cipher.
+ * <p>
+ * 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 <i>natural</i> operational direction when constructed
+ * for inclusion within a {@link Cascade}. This <i>natural</i> 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.
+ *
+ * <pre>
+ * FORWARD FORWARD
+ * +------+ +-------+
+ * | | | |
+ * | +--in --+ | +--in --+
+ * ---+ | Stage | | | Stage | +---
+ * +--out--+ | +--out--+ |
+ * | | | |
+ * +-------+ +------+
+ * </pre>
+ *
+ * <p>
+ * The second diagram shows two stages, one in a {@link Direction#FORWARD}
+ * direction, while the other is wired in a {@link Direction#REVERSED}
+ * direction.
+ *
+ * <pre>
+ * FORWARD REVERSED
+ * +------+ +------+
+ * | | | |
+ * | +--in --+ +--in --+ |
+ * ---+ | Stage | | Stage | +---
+ * +--out--+ +--out--+
+ * | |
+ * +---------------+
+ * </pre>
+ *
+ * @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
+ * <code>Stage</code>. 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 <i>plaintext</i> (if initialised in the
+ * {@link Direction#FORWARD} state) or <i>ciphertext</i> (if initialised in
+ * the {@link Direction#REVERSED} state).
+ *
+ * @param in the plaintext.
+ * @param inOffset index of <code>in</code> from which to start considering
+ * data.
+ * @param out the ciphertext.
+ * @param outOffset index of <code>out</code> 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 <i>correctness</i> 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 <code>true</code> if the implementation passes simple
+ * <i>correctness</i> tests. Returns <code>false</code> 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 <code>Transformer</code> is an abstract representation of a two-way
+ * <i>transformation</i> 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
+ * <code>Transformer</code> to close a chain is also provided.
+ * <p>
+ * A <code>Transformer</code> is characterised by the followings:
+ * <ul>
+ * <li>It can be chained to other instances, to form an {@link Assembly}.</li>
+ * <li>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 <code>Transformer</code> can be used as
+ * either in pre-processing or a post-processing modes.</li>
+ * <li>A special transformer --<code>LoopbackTransformer</code>-- is used
+ * to close the chain.</li>
+ * <li>A useful type of <code>Transformer</code> --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.</li>
+ * </ul>
+ * <p>
+ * To allow wiring <code>Transformer</code> instances together, a
+ * <i>minimal-output-size</i> in bytes is necessary. The trivial case of a
+ * value of <code>1</code> for such attribute practically means that no output
+ * buffering, from the previous element, is needed --which is independant of
+ * buffering the input if the <code>Transformer</code> 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 <code>Transformer</code>.
+ *
+ * @param mode the processing mode this <code>Transformer</code> 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 <code>true</code> if this <code>Transformer</code> was wired in
+ * pre-processing mode; <code>false</code> otherwise.
+ *
+ * @return <code>true</code> if this <code>Transformer</code> has been
+ * wired in pre-processing mode; <code>false</code> otherwise.
+ * @throws IllegalStateException if this instance has not yet been assigned an
+ * operational <i>type</i>.
+ */
+ public boolean isPreProcessing()
+ {
+ if (mode == null)
+ throw new IllegalStateException();
+ return (mode == Operation.PRE_PROCESSING);
+ }
+
+ /**
+ * Returns <code>true</code> if this <code>Transformer</code> was wired in
+ * post-processing mode; <code>false</code> otherwise.
+ *
+ * @return <code>true</code> if this <code>Transformer</code> has been
+ * wired in post-processing mode; <code>false</code> otherwise.
+ * @throws IllegalStateException if this instance has not yet been assigned an
+ * operational <i>type</i>.
+ */
+ public boolean isPostProcessing()
+ {
+ return ! isPreProcessing();
+ }
+
+ /**
+ * Initialises the <code>Transformer</code> 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 <code>Transformer</code>. A value of
+ * <code>1</code> 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 <code>Transformer</code> 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 <code>1</code> 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 <code>in</code>, starting from index position <code>0</code>
+ * 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 <code>in</code> 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 <code>1</code> 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 <code>in</code>, starting from index position <code>0</code>
+ * 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 <i>push</i> operation on this
+ * <code>Transformer</code>.
+ *
+ * @param in the input data bytes.
+ * @param offset index of <code>in</code> 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 <code>System.err</code>. If this
+ * exception has a root exception; the stack trace of the root exception is
+ * also printed to <code>System.err</code>.
+ */
+ 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://planeta.terra.com.br/informatica/paulobarreto/AnubisPage.html">The
+ * ANUBIS Block Cipher</a>.<br>
+ * <a href="mailto:paulo.barreto@terra.com.br">Paulo S.L.M. Barreto</a> and <a
+ * href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a>.</li>
+ * </ol>
+ */
+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 &lt;= N &lt;= 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
+ * <i>block size</i>.
+ *
+ * @param uk the 32N-bit user-supplied key material; 4 &lt;= N &lt;= 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li>Schneier, Bruce: <i>Applied Cryptography</i>, Second Edition, 336--339,
+ * 647--654 (1996 Bruce Schneier).</li>
+ * <li><a href="http://www.counterpane.com/blowfish.html">The Blowfish
+ * Encryption Algorithm.</a></li>
+ * </ol>
+ */
+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</a>.
+ *
+ * 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 <code>CAST5</code> (a.k.a. CAST-128) algorithm,
+ * as per <i>RFC-2144</i>, dated May 1997.
+ * <p>
+ * In this RFC, <i>Carlisle Adams</i> (the CA in CAST, ST stands for
+ * <i>Stafford Tavares</i>) describes CAST5 as:
+ * <blockquote>
+ * "...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."
+ * </blockquote>
+ * <p>
+ * <code>CAST5</code> 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.
+ * <p>
+ * The <code>CAST5</code> encryption algorithm has been designed to allow a
+ * key size that can vary from <code>40</code> bits to <code>128</code> bits,
+ * in 8-bit increments (that is, the allowable key sizes are <code>40, 48, 56,
+ * 64, ..., 112, 120,</code> and <code>128</code> bits. For variable keysize
+ * operation, the specification is as follows:
+ * <ol>
+ * <li>For key sizes up to and including <code>80</code> bits (i.e.,
+ * <code>40, 48, 56, 64, 72,</code> and <code>80</code> bits), the algorithm
+ * is exactly as specified but uses <code>12</code> rounds instead of
+ * <code>16</code>;</li>
+ * <li>For key sizes greater than <code>80</code> bits, the algorithm uses
+ * the full <code>16</code> rounds;</li>
+ * <li>For key sizes less than <code>128</code> bits, the key is padded with
+ * zero bytes (in the rightmost, or least significant, positions) out to
+ * <code>128</code> bits (since the <code>CAST5</code> key schedule assumes
+ * an input key of <code>128</code> bits).</li>
+ * </ol>
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2144.txt">The CAST-128 Encryption
+ * Algorithm</a>.<br>
+ * <a href="mailto:cadams@entrust.com">Carlisle Adams</a>.</li>
+ * </ol>
+ */
+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.
+ * <pre>
+ * INPUT: plaintext m1...m64; key K = k1...k128.
+ * OUTPUT: ciphertext c1...c64.
+ * </pre>
+ * <ol>
+ * <li>(key schedule) Compute 16 pairs of subkeys {Kmi, Kri} from a user
+ * key (see makeKey() method).</li>
+ * <li>(L0,R0) <-- (m1...m64). (Split the plaintext into left and right
+ * 32-bit halves L0 = m1...m32 and R0 = m33...m64.).</li>
+ * <li>(16 rounds) for i from 1 to 16, compute Li and Ri as follows:
+ * <ul>
+ * <li>Li = Ri-1;</li>
+ * <li>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.</li>
+ * </ul>
+ * <li>c1...c64 <-- (R16,L16). (Exchange final blocks L16, R16 and
+ * concatenate to form the ciphertext.)</li>
+ * </ol>
+ * <p>
+ * 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).
+ * <p>
+ * Looking at the iterations/rounds in pairs we have:
+ * <pre>
+ * (1a) Li = Ri-1;
+ * (1b) Ri = Li-1 ^ Fi(Ri-1);
+ * (2a) Li+1 = Ri;
+ * (2b) Ri+1 = Li ^ Fi+1(Ri);
+ * </pre>
+ * which by substituting (2a) in (2b) becomes
+ * <pre>
+ * (2c) Ri+1 = Li ^ Fi+1(Li+1);
+ * </pre>
+ * by substituting (1b) in (2a) and (1a) in (2c), we get:
+ * <pre>
+ * (3a) Li+1 = Li-1 ^ Fi(Ri-1);
+ * (3b) Ri+1 = Ri-1 ^ Fi+1(Li+1);
+ * </pre>
+ * Using only one couple of variables L and R, initialised to L0 and R0
+ * respectively, the assignments for each pair of rounds become:
+ * <pre>
+ * (4a) L ^= Fi(R);
+ * (4b) R ^= Fi+1(L);
+ * </pre>
+ *
+ * @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 <i>Factory</i> 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
+ * <code>null</code> 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 <i>Factory</i>.
+ *
+ * @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).
+ * <p>
+ * New applications should not use DES except for compatibility.
+ * <p>
+ * This version is based upon the description and sample implementation in
+ * [1].
+ * <p>
+ * References:
+ * <ol>
+ * <li>Bruce Schneier, <i>Applied Cryptography: Protocols, Algorithms, and
+ * Source Code in C, Second Edition</i>. (1996 John Wiley and Sons) ISBN
+ * 0-471-11709-9. Pages 265--301, 623--632.</li>
+ * </ol>
+ */
+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 <code>true</code> if the first 8 bytes of <i>kb</i> have been
+ * parity adjusted. <code>false</code> 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 <code>true</code> 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 <code>true</code> 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 <code>true</code> if <code>kb</code>represents a possibly weak key.
+ * Returns <code>false</code> 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.
+ * <p>
+ * A symmetric key block cipher is a function that maps n-bit plaintext blocks
+ * to n-bit ciphertext blocks; n being the cipher's <i>block size</i>. This
+ * encryption function is parameterised by a k-bit key, and is invertible. Its
+ * inverse is the decryption function.
+ * <p>
+ * Possible initialisation values for an instance of this type are:
+ * <ul>
+ * <li>The block size in which to operate this block cipher instance. This
+ * value is <b>optional</b>, if unspecified, the block cipher's default block
+ * size shall be used.</li>
+ * <li>The byte array containing the user supplied key material to use for
+ * generating the cipher's session key(s). This value is <b>mandatory</b> and
+ * should be included in the initialisation parameters. If it isn't, an
+ * {@link IllegalStateException} will be thrown if any method, other than
+ * <code>reset()</code> 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.</li>
+ * </ul>
+ * <p>
+ * <b>IMPLEMENTATION NOTE</b>: Although all the concrete classes in this
+ * package implement the {@link Cloneable} interface, it is important to note
+ * here that such an operation <b>DOES NOT</b> 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 <b>same block size</b> 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 <code>in</code> from which to start considering
+ * data.
+ * @param out the ciphertext.
+ * @param outOffset index of <code>out</code> 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 <code>in</code> from which to start considering
+ * data.
+ * @param out the ciphertext.
+ * @param outOffset index of <code>out</code> 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 <i>correctness</i> 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 <code>true</code> if the implementation passes simple
+ * <i>correctness</i> tests. Returns <code>false</code> 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 <code>Iterator</code> 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 <code>Iterator</code> over the supported key sizes.
+ */
+ Iterator keySizes();
+
+ /**
+ * Expands a user-supplied key material into a session key for a designated
+ * <i>block size</i>.
+ *
+ * @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 <code>in</code> from which to start considering
+ * data.
+ * @param out the ciphertext.
+ * @param outOffset index of <code>out</code> 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 <code>in</code> from which to start considering
+ * data.
+ * @param out the plaintext.
+ * @param outOffset index of <code>out</code> 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 <i>correctness</i> 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 <code>true</code> if the implementation passes simple
+ * <i>correctness</i> tests. Returns <code>false</code> 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://planeta.terra.com.br/informatica/paulobarreto/KhazadPage.html">The
+ * Khazad Block Cipher</a>.<br>
+ * <a href="mailto:paulo.barreto@terra.com.br">Paulo S.L.M. Barreto</a> and <a
+ * href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a>.</li>
+ * </ol>
+ */
+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
+ * <i>block size</i>.
+ *
+ * @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.
+ * <p>
+ * 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.esat.kuleuven.ac.be/~rijmen/rijndael/">The Rijndael
+ * Block Cipher - AES Proposal</a>.<br>
+ * <a href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a> and
+ * <a href="mailto:daemen.j@protonworld.com">Joan Daemen</a>.</li>
+ * </ol>
+ */
+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
+ * <i>block size</i>.
+ *
+ * @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.
+ * <p>
+ * Serpent was designed by Ross Anderson, Eli Biham, and Lars Knudsen as a
+ * proposed cipher for the Advanced Encryption Standard.
+ * <p>
+ * 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 <a
+ * href="http://www.ii.uib.no/~osvik/">Dag Arne Osvik</a>, which are optimized
+ * for the Pentium family of processors.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.cl.cam.ac.uk/~rja14/serpent.html">Serpent: A
+ * Candidate Block Cipher for the Advanced Encryption Standard.</a></li>
+ * </ol>
+ */
+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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.esat.kuleuven.ac.be/~rijmen/square/">The block
+ * cipher Square</a>.<br>
+ * <a href="mailto:daemen.j@protonworld.com">Joan Daemen</a>, <a
+ * href="mailto:lars.knudsen@esat.kuleuven.ac.be">Lars Knudsen</a> and <a
+ * href="mailto:vincent.rijmen@esat.kuleuven.ac.be">Vincent Rijmen</a>.</li>
+ * </ol>
+ */
+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 <i>in</i> in order to produce in
+ * <i>out</i> an internal session sub-key.
+ * <p>
+ * Both <i>in</i> and <i>out</i> are arrays of four ints.
+ * <p>
+ * Pseudo-code is:
+ * <pre>
+ * for (i = 0; i &lt; 4; i++)
+ * {
+ * out[i] = 0;
+ * for (j = 0, n = 24; j &lt; 4; j++, n -= 8)
+ * {
+ * k = mul(in[i] &gt;&gt;&gt; 24, G[0][j]) &circ; mul(in[i] &gt;&gt;&gt; 16, G[1][j])
+ * &circ; mul(in[i] &gt;&gt;&gt; 8, G[2][j]) &circ; mul(in[i], G[3][j]);
+ * out[i] &circ;= k &lt;&lt; n;
+ * }
+ * }
+ * </pre>
+ */
+ 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).
+ * <p>
+ * For best performance call it with abs(b) &lt; 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 <i>combined cipher</i> that uses three
+ * iterations of the Data Encryption Standard cipher to theoretically improve
+ * the security of plain DES, at the cost of speed.
+ * <p>
+ * 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.
+ * <p>
+ * To encrypt:
+ * <blockquote><i>C<sub>i</sub> = E<sub>k3</sub> ( E<sub>k2</sub><sup>-1</sup> (
+ * E<sub>k1</sub> ( P<sub>i</sub> )))</i>
+ * </blockquote>
+ * <p>
+ * And to decrypt:
+ * <blockquote><i>P<sub>i</sub> = E<sub>k1</sub><sup>-1</sup> (
+ * E<sub>k2</sub> ( E<sub>k3</sub><sup>-1</sup> ( C<sub>i</sub> )))</i>
+ * </blockquote>
+ * <p>
+ * (The "ede" comes from the encryption operation, which runs
+ * Encrypt-Decrypt-Encrypt)
+ * <p>
+ * References:
+ * <ol>
+ * <li>Bruce Schneier, <i>Applied Cryptography: Protocols, Algorithms, and
+ * Source Code in C, Second Edition</i>. (1996 John Wiley and Sons) ISBN
+ * 0-471-11709-9. Page 294--295.</li>
+ * </ol>
+ */
+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 <code>3</code> 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
+ * <code>1</code>, <code>2</code> or <code>3</code>. 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
+ * <code>8 * keyCount</code> bytes starting at offset position
+ * <code>offset</code>, 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 <code>3</code> as the value of the first parameter.
+ *
+ * @param kb The key bytes to test.
+ * @param offset The starting offset into the key bytes.
+ * @return <code>true</code> if the bytes in <i>kb</i> starting at
+ * <i>offset</i> 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
+ * <code>1</code>, <code>2</code> or <code>3</code>. 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
+ * <code>8 * keyCount</code> bytes starting at offset position
+ * <code>offset</code>, otherwise an
+ * {@link ArrayIndexOutOfBoundsException} will be raised.
+ * @param offset the starting offset into the array.
+ * @return <code>true</code> if the bytes in <i>kb</i> starting at
+ * <i>offset</i> 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.
+ * <p>
+ * Twofish is designed by Bruce Schneier, Doug Whiting, John Kelsey, Chris
+ * Hall, David Wagner and Niels Ferguson.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.counterpane.com/twofish-paper.html">Twofish: A
+ * 128-bit Block Cipher</a>.</li>
+ * </ol>
+ */
+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:<p>
+ * <pre>
+ * g(x) = x**4 + (a + 1/a) x**3 + a x**2 + (a + 1/a) x + 1
+ * </pre>
+ * 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
+ * <i>block size</i>.
+ *
+ * @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.
+ * <p>
+ * 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 <code>n + 1</code> 8-byte blocks where
+ * <code>n</code> 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.
+ * <p>
+ * 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 <code>n - 1</code> 8-byte blocks where
+ * <code>n</code> 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 <i>Service Provider Interface</i> (<b>SPI</b>)
+ * 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 <i>Service Provider Interface</i> (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <code>CAST5</code> (a.k.a. CAST-128) <i>Service
+ * Provider Interface</i> (<b>SPI</b>) 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} <i>Adapter</i> class to wrap
+ * GNU cipher instances.
+ * <p>
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for
+ * the {@link Cipher} class, which provides the functionality of symmetric-key
+ * block ciphers, such as the AES.
+ * <p>
+ * 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 <code>key</code> is invalid or the cipher
+ * needs extra parameters which can not be derived from
+ * <code>key</code>; 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 <i>Service Provider Interface</i> (<b>SPI</b>)
+ * 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
+ * <code>DSS</code> 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
+ * <code>wrappedKeyType</code> is an inappropriate type for the
+ * unwrapped key.
+ * @throws NoSuchAlgorithmException If the <code>wrappedKeyAlgorithm</code>
+ * 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.
+ * <p>
+ * This default implementation ALWAYS returns the smallest multiple of the
+ * <code>kwaBlockSize</code> --passed to this method through its
+ * constructor-- greater than or equal to the designated
+ * <code>inputLength</code>.
+ *
+ * @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.
+ * <p>
+ * This default implementation ALWAYS returns the smallest multiple of the
+ * <code>paddingBlockSize</code> --passed to this method through its
+ * constructor-- greater than or equal to the designated
+ * <code>inputLength</code>.
+ *
+ * @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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Adapter</i> 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 <code>alias</code>. Return
+ * <code>null</code> if <code>alias</code> was not found in
+ * <code>keyring</code>.
+ */
+ 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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.
+ * <p>
+ * This class defines the <i>Service Provider Interface</i> (<b>SPI</b>) for
+ * the {@link javax.crypto.Mac} class, which provides the functionality of a
+ * message authentication code algorithm, such as the <i>Hashed Message
+ * Authentication Code</i> (<b>HMAC</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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 <i>Service Provider Interface</i>
+ * (<b>SPI</b>) 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).
+ * <p>
+ * For GNU block ciphers we will define these parameters as
+ * <pre>
+ * BlockCipherParameters ::= SEQUENCE {
+ * blockSize INTEGER,
+ * keySize INTEGER,
+ * initializationVector OCTET STRING OPTIONAL }
+ * </pre>
+ *
+ * @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 <i>Service Provider Interface</i> (<b>SPI</b>) 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 <i>Service
+ * Provider Interface</i> (<b>SPI</b>) 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 <em>Adapter</em> 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 <em>Adapter</em> 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:
+ *
+ * <pre>
+ * DhParams ::= SEQUENCE {
+ * p INTEGER, -- odd prime, p=jq +1
+ * g INTEGER, -- generator, g
+ * q INTEGER -- factor of p-1
+ * }
+ * </pre>
+ */
+ 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:
+ *
+ * <pre>
+ * DhParams ::= SEQUENCE {
+ * p INTEGER, -- odd prime, p=jq +1
+ * g INTEGER, -- generator, g
+ * q INTEGER -- factor of p-1
+ * }
+ * </pre>
+ */
+ 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 <code>null</code> 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 <code>null</code> 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}.
+ * <p>
+ * 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 <code>null</code> 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 <i>Nonce</i> material used to
+ * initialize the algorithm.
+ */
+public class UMac32ParameterSpec
+ implements AlgorithmParameterSpec
+{
+ /** The <i>Nonce</i> 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 <code>null</code> 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 <code>true</code> 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
+ * <code>init()</code> or <code>reset()</code>.
+ *
+ * @return <code>true</code> if this party has completed its part of the key
+ * agreement protocol exchange; <code>false</code> 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.
+ * <p>
+ * Calls the method with the same name and three arguments as:
+ * <code>getInstance(raw, 0, raw.length)</code>.
+ *
+ * @param raw the encoded form, excluding the header bytes.
+ * @return a new instance of <code>IncomingMessage</code>.
+ */
+ 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 <code>IncomingMessage</code>.
+ */
+ 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.
+ * <p>
+ * 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.
+ * <p>
+ * 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 <code>null</code> <i>root</i> cause exception. */
+ private Throwable cause = null;
+
+ /**
+ * Constructs a new instance of <code>KeyAgreementException</code>. The
+ * root exception and the detailed message are <code>null</code>.
+ */
+ public KeyAgreementException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a new instance of <code>KeyAgreementException</code> with a
+ * detailed message. The <i>root</i> exception is <code>null</code>.
+ *
+ * @param detail a possibly <code>null</code> string containing details of
+ * the exception.
+ * @see Throwable#getMessage()
+ */
+ public KeyAgreementException(String detail)
+ {
+ super(detail);
+ }
+
+ /**
+ * Constructs a new instance of <code>KeyAgreementException</code> with a
+ * detailed message and a <i>root</i> exception.
+ *
+ * @param detail a possibly <code>null</code> string containing details of
+ * the exception.
+ * @param cause a possibly <code>null</code> 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 <code>null</code> if the cause is
+ * nonexistent or unknown. The <i>cause</i> is the throwable that caused this
+ * exception to be thrown.
+ *
+ * @return the possibly <code>null</code> exception that caused this one.
+ */
+ public Throwable getCause()
+ {
+ return cause;
+ }
+
+ /**
+ * Prints this exception's stack trace to <code>System.err</code>. If this
+ * exception has a <i>root</i> exception; the stack trace of the <i>root</i>
+ * exception is also printed to <code>System.err</code>.
+ */
+ 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 <i>root</i> exception; the stack trace of the <i>root</i> 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 <i>root</i> exception; the stack trace of the <i>root</i> 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 <i>root</i> 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 <i>Factory</i> class to generate key agreement protocol handlers.
+ */
+public class KeyAgreementFactory
+{
+ /** Trivial constructor to enforce <i>Singleton</i> pattern. */
+ private KeyAgreementFactory()
+ {
+ super();
+ }
+
+ /**
+ * Returns an instance of a key agreeent protocol handler, for party
+ * <code>A</code> in a two-party <code>A..B</code> exchange, given the
+ * canonical name of this protocol. Party <code>A</code> 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
+ * <code>A</code>, or <code>null</code> 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
+ * <code>B</code> in a two-party <code>A..B</code> 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
+ * <code>B</code>, or <code>null</code> 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
+ * <i>Factory</i>.
+ *
+ * @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.
+ * <p>
+ * 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.
+ * <pre>
+ * key --&gt; 4-byte-length || 1-byte-type-and-format || encoded-key-bytes
+ * </pre>
+ *
+ * @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.
+ * <p>
+ * 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.
+ * <pre>
+ * key --&gt; 4-byte-length || 1-byte-type-and-format || encoded-key-bytes
+ * </pre>
+ *
+ * @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 <code>0</code> to <code>3</code> 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 <i>PrivateKeyInfo</i>
+ * representation of a DH private key. The ASN.1 specification is as follows:
+ *
+ * <pre>
+ * 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
+ * }
+ * </pre>
+ * <p>
+ * <b>IMPORTANT</b>: 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 <code>null</code> for the <code>q</code>
+ * parameter. RFC-2631 DOES NOT allow for an <i>optional</i> value for that
+ * parameter, hence we replace such null values with <code>0</code>, and do
+ * the reverse in the corresponding decode method.
+ *
+ * @return the DER encoded form of the ASN.1 representation of the
+ * <i>PrivateKeyInfo</i> 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
+ * <i>PrivateKeyInfo</i> material fed as <code>input</code>.
+ * @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
+ * <i>Raw</i> 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 <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for a DH public key, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_DH_PUBLIC_KEY},</li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>q</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>q</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>p</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>p</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>g</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>g</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>y</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>y</code>,
+ * </li>
+ * </ol>
+ *
+ * @param key the key to encode.
+ * @return the <i>Raw</i> 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 <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for a DH private key, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_DH_PRIVATE_KEY},</li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>q</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>q</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>p</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>p</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>g</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>g</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the DH parameter
+ * <code>x</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the DH parameter <code>x</code>,
+ * </li>
+ * </ol>
+ *
+ * @param key the key to encode.
+ * @return the <i>Raw</i> 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 <i>SubjectPublicKeyInfo</i>
+ * representation of a DH public key. The ASN.1 specification, as defined in
+ * RFC-3280, and RFC-2459, is as follows:
+ *
+ * <pre>
+ * 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
+ * }
+ * </pre>
+ *
+ * <p>The <i>subjectPublicKey</i> field, which is a BIT STRING, contains the
+ * DER-encoded form of the DH public key as an INTEGER.</p>
+ *
+ * <pre>
+ * DHPublicKey ::= INTEGER -- public key, y = g^x mod p
+ * </pre>
+ * <p>
+ * <b>IMPORTANT</b>: 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 <code>null</code> for the <code>q</code>
+ * parameter. RFC-2631 DOES NOT allow for an <i>optional</i> value for that
+ * parameter, hence we replace such null values with <code>0</code>, 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
+ * <i>SubjectPublicKeyInfo</i> in an X.509 certificate.
+ * @throw InvalidParameterException if <code>key</code> 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
+ * <i>SubjectPublicKeyInfo</i> 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:
+ * <ul>
+ * <li>An appropriate prime p and generator g of Z<sub>p</sub><sup>*</sup>
+ * (2 &lt;= g &lt;= p-2) are selected and published.</li>
+ * <li>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.</li>
+ * <li>A chooses a random secret x, 1 &lt;= x &lt;= p-2, and sends B message
+ * (1) which is g^x mod p.</li>
+ * <li>B chooses a random secret y, 1 &lt;= y &lt;= p-2, and sends A message
+ * (2) which is g^y mod p.</li>
+ * <li>B receives message (1) and computes the shared key as K = (g^x)^y mod p.
+ * </li>
+ * <li>A receives message (2) and computes the shared key as K = (g^y)^x mod p.
+ * </li>
+ * </ul>
+ * <p>
+ * RFC-2631 describes a <i>Static-Static Mode</i> of operations with
+ * Diffie-Hellman keypairs as follows:
+ * <pre>
+ * &quot;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.&quot;
+ * </pre>
+ *
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * <li><a href="http://www.cacr.math.uwaterloo.ca/hac">[HAC]</a>: Handbook of
+ * Applied Cryptography.<br>
+ * CRC Press, Inc. ISBN 0-8493-8523-7, 1997<br>
+ * Menezes, A., van Oorschot, P. and S. Vanstone.</li>
+ * </ol>
+ */
+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:
+ * <ul>
+ * <li>A sends to B a single message allowing one-pass key agreement.</li>
+ * <li>A obtains an authentic copy of B's public key (p, g, yb), where yb =
+ * g**xb.</li>
+ * <li>A chooses a random integer x, 1 &lt;= x &lt;= p-2, and sends B the
+ * message g**x. A computes the shared secret key K as yb**x.</li>
+ * <li>B computes the same key K on receipt of the previous message as
+ * (g**x)**xb.</li>
+ * </ul>
+ * <p>
+ * RFC-2631 describes an <i>Ephemeral-Static Mode</i> of operations with
+ * Diffie-Hellman keypairs as follows:
+ * <pre>
+ * &quot;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.&quot;
+ * </pre>
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * <li><a href="http://www.cacr.math.uwaterloo.ca/hac">[HAC]</a>: Handbook of
+ * Applied Cryptography.<br>
+ * CRC Press, Inc. ISBN 0-8493-8523-7, 1997<br>
+ * Menezes, A., van Oorschot, P. and S. Vanstone.</li>
+ * </ol>
+ */
+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: <code>p</code>, and <code>g</code>.
+ * <p>
+ * According to the JDK, cryptographic <i>Keys</i> all have a <i>format</i>.
+ * The format used in this implementation is called <i>Raw</i>, 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 <code>getEncoded()</code> methods of each of the private and
+ * public keys.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+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 <code>true</code> 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 <code>true</code> 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.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+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 <code>GnuDHPrivateKey</code> 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 <code>encodePrivateKey()</code>
+ * 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
+ * <code>k</code>, 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 <code>true</code> 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 <code>true</code> 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.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+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 <code>GnuDHPublicKey</code> 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 <code>encodePublicKey()</code>
+ * 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
+ * <code>k</code>, 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 <code>true</code> 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 <code>true</code> 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.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc2631.txt">Diffie-Hellman Key
+ * Agreement Method</a><br>
+ * Eric Rescorla.</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+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:
+ * <pre>
+ * 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
+ * &circ; (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 &quot;:&quot; p)) (s is chosen randomly)
+ * v = g&circ;x (computes password verifier)
+ *
+ * The host then keeps {I, s, v} in its password database.
+ *
+ * The authentication protocol itself goes as follows:
+ * User -&gt; Host: I, A = g&circ;a (identifies self, a = random number)
+ * Host -&gt; User: s, B = 3v + g&circ;b (sends salt, b = random number)
+ *
+ * Both: u = H(A, B)
+ *
+ * User: x = H(s, p) (user enters password)
+ * User: S = (B - 3g&circ;x) &circ; (a + ux) (computes session key)
+ * User: K = H(S)
+ *
+ * Host: S = (Av&circ;u) &circ; b (computes session key)
+ * Host: K = H(S)
+ * </pre>
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+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).
+ * <p>
+ * In this alternative, the exchange goes as follows:
+ *
+ * <pre>
+ * C -&gt; S: I (identifies self)
+ * S -&gt; C: N, g, s, B = 3v + g&circ;b (sends salt, b = random number)
+ * C -&gt; S: A = g&circ;a (a = random number)
+ * </pre>
+ *
+ * <p>
+ * All elements are computed the same way as in the standard version.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
+ * Secure Remote Password Authentication Mechanism</a><br>
+ * K. Burdis, R. Naffah.</li>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+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).
+ * <p>
+ * In this alternative, the exchange goes as follows:
+ *
+ * <pre>
+ * C -&gt; S: I (identifies self)
+ * S -&gt; C: N, g, s, B = 3v + g&circ;b (sends salt, b = random number)
+ * C -&gt; S: A = g&circ;a (a = random number)
+ * </pre>
+ *
+ * <p>
+ * All elements are computed the same way as in the standard version.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
+ * Secure Remote Password Authentication Mechanism</a><br>
+ * K. Burdis, R. Naffah.</li>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+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 <a
+ * href="http://www.ietf.org/internet-drafts/draft-ietf-tls-srp-05.txt">Using
+ * SRP for TLS Authentication</a>. The only difference between it and the SASL
+ * variant is that the shared secret is the entity <code>S</code> and not
+ * <code>H(S)</code>.
+ */
+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 <a
+ * href="http://www.ietf.org/internet-drafts/draft-ietf-tls-srp-05.txt">Using
+ * SRP for TLS Authentication</a>. The only difference between it and the SASL
+ * variant is that the shared secret is the entity <code>S</code> and not
+ * <code>H(S)</code>.
+ */
+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.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * This object encapsulates the two numbers:
+ * <ul>
+ * <li><b>N</b>: A large safe prime (N = 2q+1, where q is prime).</li>
+ * <li><b>g</b>: A generator modulo N.</li>
+ * </ul>
+ * <p>
+ * Note that in SRP, all arithmetic is done modulo N.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+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 <code>N</code>.
+ */
+ public BigInteger getN()
+ {
+ return N;
+ }
+
+ /**
+ * Returns the generator.
+ *
+ * @return <code>g</code>.
+ */
+ public BigInteger getG()
+ {
+ return g;
+ }
+
+ /**
+ * Returns <code>true</code> if the designated object is an instance of
+ * <code>SRPKey</code> and has the same SRP parameter values as this one.
+ *
+ * @param obj the other non-null SRP key to compare to.
+ * @return <code>true</code> 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:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+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
+ * <i>Raw</i> format to use with SRP keypairs.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+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
+ * <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for an SRP public key, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_SRP_PUBLIC_KEY},</li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the SRP parameter
+ * <code>N</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the SRP parameter <code>N</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the SRP parameter
+ * <code>g</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the SRP parameter <code>g</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the SRP parameter
+ * <code>y</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the SRP parameter <code>y</code>,
+ * </li>
+ * </ol>
+ *
+ * @param key the key to encode.
+ * @return the <i>Raw</i> 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
+ * <i>Raw</i> format supported by this library.
+ * <p>
+ * The <i>Raw</i> format for an SRP private key, in this implementation, is a
+ * byte sequence consisting of the following:
+ * <ol>
+ * <li>4-byte magic consisting of the value of the literal
+ * {@link Registry#MAGIC_RAW_SRP_PRIVATE_KEY},</li>
+ * <li>1-byte version consisting of the constant: 0x01,</li>
+ * <li>4-byte count of following bytes representing the SRP parameter
+ * <code>N</code> in internet order,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the SRP parameter <code>N</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the SRP parameter
+ * <code>g</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the SRP parameter <code>g</code>,
+ * </li>
+ * <li>4-byte count of following bytes representing the SRP parameter
+ * <code>x</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the SRP parameter <code>x</code>,
+ * </li>
+ * <li>one byte which indicates whether the SRP parameter <code>v</code> is
+ * included in this encoding (value <code>0x01</code>) or not (value
+ * <code>0x00</code>).</li>
+ * <li>4-byte count of following bytes representing the SRP parameter
+ * <code>v</code>,</li>
+ * <li>n-bytes representation of a {@link BigInteger} obtained by invoking
+ * the <code>toByteArray()</code> method on the SRP parameter <code>v</code>,
+ * </li>
+ * </ol>
+ *
+ * @param key the key to encode.
+ * @return the <i>Raw</i> 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.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+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:
+ * <ol>
+ * <li>v (server side): the user's verifier.</li>
+ * <li>X (both sides): the server's or client's ephemeral private
+ * exponent.</li>
+ * </ol>
+ */
+ 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 <code>encodePrivateKey()</code>
+ * 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
+ * <code>k</code>, 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 <code>null</code> 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 <code>true</code> if the designated object is an instance of
+ * <code>SRPPrivateKey</code> and has the same SRP parameter values as this
+ * one.
+ *
+ * @param obj the other non-null SRP key to compare to.
+ * @return <code>true</code> 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.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+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 <code>encodePublicKey()</code>
+ * 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
+ * <code>k</code>, 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 <code>true</code> if the designated object is an instance of
+ * <code>SRPPublicKey</code>and has the same SRP parameter values as this
+ * one.
+ *
+ * @param obj the other non-null SRP key to compare to.
+ * @return <code>true</code> 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 <b>must</b> 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
+ * <code>null</code> 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 <code>null</code> 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 <code>true</code> if <code>alias</code> was present and was
+ * successfully trmoved. Returns <code>false</code> if
+ * <code>alias</code> 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 <i>keyring:</i> a file that is used to store
+ * and protect public and private cryptographic keys.
+ * <p>
+ * A <i>keyring</i> is modelled as a mapping of one <i>alias</i> to one or
+ * more <i>entries</i> (optionally of different types).
+ * <p>
+ * See also the sub-interfaces {@link IPublicKeyring} and
+ * {@link IPrivateKeyring} for special types of <i>keyrings</i> --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.
+ * <p>
+ * 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 <code>attributes</code>.
+ *
+ * @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 <i>alias</i>
+ * 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 <code>alias</code>, or <code>null</code> 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 <code>alias</code>, or <code>null</code> if no one
+ * {@link Entry} can be found with the designated <code>alias</code>.
+ */
+ List get(String alias);
+
+ /**
+ * Adds a designated {@link Entry} to this keyring.
+ * <p>
+ * 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 <code>alias</code> from this
+ * keyring. Does nothing if there was no such entry.
+ * <p>
+ * 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
+ * <i>alias</i>.
+ * <p>
+ * What about public keys? and certificate-path?
+ */
+public interface IPrivateKeyring
+ extends IKeyring
+{
+ /**
+ * Tests if this keyring contains a private key entry with the given
+ * <code>alias</code>.
+ *
+ * @param alias The alias to check.
+ * @return <code>true</code> if this keyring contains a private key with the
+ * given <code>alias</code>; <code>false</code> otherwise.
+ */
+ boolean containsPrivateKey(String alias);
+
+ /**
+ * Returns the private key with the given <code>alias</code>.
+ *
+ * @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; <code>null</code> 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
+ * <code>alias</code>.
+ *
+ * @param alias The alias to test.
+ * @return <code>true</code> if this keyring contains a public key entry
+ * with the given <code>alias</code>; <code>false</code>
+ * otherwise.
+ */
+ boolean containsPublicKey(String alias);
+
+ /**
+ * Returns the public key with the given <code>alias</code>, or
+ * <code>null</code> if there is no such entry.
+ *
+ * @param alias The alias of the public key to find.
+ * @return The public key; or <code>null</code> 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
+ * <code>alias</code>.
+ *
+ * @param alias The alias to check.
+ * @return <code>true</code> if this keyring contains a certificate path
+ * with the given <code>alias</code>; <code>false</code>
+ * otherwise.
+ */
+ boolean containsCertPath(String alias);
+
+ /**
+ * Returns the certificate path with the given <code>alias</code>, or
+ * <code>null</code> if there is no such entry.
+ *
+ * @param alias The alias of the certificate path to find.
+ * @return The certificate path for the designated <code>alias</code>; or
+ * <code>null</code> 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
+ * <code>alias</code>.
+ *
+ * @param alias The alias of the certificate to check.
+ * @return <code>true</code> if this keyring contains a certificate entry
+ * that has the given <code>alias</code>; <code>false</code>
+ * otherwise.
+ */
+ boolean containsCertificate(String alias);
+
+ /**
+ * Returns a certificate that has the given <code>alias</code>, or
+ * <code>null</code> if this keyring has no such entry.
+ *
+ * @param alias The alias of the certificate to find.
+ * @return The certificate with the designated <code>alias</code>, or
+ * <code>null</code> if none found.
+ */
+ Certificate getCertificate(String alias);
+
+ /**
+ * Adds a certificate in this keyring, with the given <code>alias</code>.
+ * <p>
+ * 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 <code>(name =&gt; value)</code> 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].
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://csrc.nist.gov/encryption/kms/key-wrap.pdf"></a>.</li>
+ * <li><a href="http://www.rfc-archive.org/getrfc.php?rfc=3394">Advanced
+ * Encryption Standard (AES) Key Wrap Algorithm</a>.</li>
+ * <li><a href="http://www.w3.org/TR/xmlenc-core/">XML Encryption Syntax and
+ * Processing</a>.</li>
+ * </ol>
+ */
+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 <code>in</code> 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 <code>out</code> of the first wrapped
+ * byte.
+ * @return the number of bytes of the wrapped key material; i.e. the length,
+ * in <code>out</code>, starting from <code>outOffset</code>
+ * 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 <code>in</code> 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 <code>in</code> 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 <code>out</code> of the first unwrapped
+ * byte.
+ * @return the number of bytes of the unwrapped key material; i.e. the length,
+ * in <code>out</code>, starting from <code>outOffset</code>
+ * 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 <code>in</code> 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
+ * <code>null</code> 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
+ * <i>Factory</i>.
+ *
+ * @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].
+ * <p>
+ * <b>IMPORTANT</b>: This class is NOT thread safe.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.rfc-archive.org/getrfc.php?rfc=3217">Triple-DES and
+ * RC2 Key Wrapping</a>.</li>
+ * <li><a href="http://www.w3.org/TR/xmlenc-core/">XML Encryption Syntax and
+ * Processing</a>.</li>
+ * </ol>
+ */
+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 <i>MAC</i> (Message Authentication Code)
+ * implementations.
+ */
+public abstract class BaseMac
+ implements IMac
+{
+ /** The canonical name prefix of the <i>MAC</i>. */
+ 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 <i>HMAC</i> (Keyed-Hash Message Authentication
+ * Code).
+ * <p>
+ * <i>HMAC</i> can be used in combination with any iterated cryptographic hash
+ * function. <i>HMAC</i> also uses a <i>secret key</i> for calculation and
+ * verification of the message authentication values. The main goals behind this
+ * construction are:
+ * <ul>
+ * <li>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.</li>
+ * <li>To preserve the original performance of the hash function without
+ * incurring a significant degradation.</li>
+ * <li>To use and handle keys in a simple way.</li>
+ * <li>To have a well understood cryptographic analysis of the strength of the
+ * authentication mechanism based on reasonable assumptions on the underlying
+ * hash function.</li>
+ * <li>To allow for easy replaceability of the underlying hash function in case
+ * that faster or more secure hash functions are found or required.</li>
+ * </ul>
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc-2104.txt">RFC 2104</a>HMAC:
+ * Keyed-Hashing for Message Authentication.<br>
+ * H. Krawczyk, M. Bellare, and R. Canetti.</li>
+ * </ol>
+ */
+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 <i>Factory</i> to instantiate Keyed-Hash Message Authentication Code
+ * (HMAC) algorithm instances.
+ */
+public class HMacFactory
+ implements Registry
+{
+ /** Trivial constructor to enforce <i>Singleton</i> pattern. */
+ private HMacFactory()
+ {
+ super();
+ }
+
+ /**
+ * Return an instance of a <i>HMAC</i> 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 <i>HMAC</i> algorithm, or <code>null</code>
+ * 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;
+ }
+
+ /**
+ * <p>
+ * Returns a {@link java.util.Set} of names of <i>HMAC</i> algorithms
+ * supported by this <i>Factory</i>.
+ * </p>
+ *
+ * @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.
+ * <p>
+ * A <i>MAC</i> provides a way to check the integrity of information
+ * transmitted over, or stored in, an unreliable medium, based on a secret key.
+ * Typically, <i>MAC</i>s are used between two parties, that share a common
+ * secret key, in order to validate information transmitted between them.
+ * <p>
+ * When a <i>MAC</i> algorithm is based on a cryptographic hash function, it is
+ * then called to a <i>HMAC</i> (Hashed Message Authentication Code) --see <a
+ * href="http://www.ietf.org/rfc/rfc-2104.txt">RFC-2104</a>.
+ * <p>
+ * Another type of <i>MAC</i> algorithms exist: UMAC or <i>Universal Message
+ * Authentication Code</i>, described in <a
+ * href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">
+ * draft-krovetz-umac-01.txt</a>.
+ * <p>
+ * With <i>UMAC</i>s, the sender and receiver share a common secret key (the
+ * <i>MAC</i> key) which determines:
+ * <ul>
+ * <li>The key for a <i>universal hash function</i>. This hash function is
+ * <i>non-cryptographic</i>, in the sense that it does not need to have any
+ * cryptographic <i>hardness</i> property. Rather, it needs to satisfy some
+ * combinatorial property, which can be proven to hold without relying on
+ * unproven hardness assumptions.</li>
+ * <li>The key for a <i>pseudorandom function</i>. This is where one needs a
+ * cryptographic hardness assumption. The pseudorandom function may be obtained
+ * from a <i>block cipher</i> or a <i>cryptographic hash function</i>. </li>
+ * </ul>
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc-2104.txt">RFC 2104</a>HMAC:
+ * Keyed-Hashing for Message Authentication.<br>
+ * H. Krawczyk, M. Bellare, and R. Canetti.</li>
+ * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">
+ * UMAC</a>: Message Authentication Code using Universal Hashing.<br>
+ * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * This implementation, follows the recommendation of the <i>RFC 2104</i>
+ * authors; specifically:
+ * <pre>
+ * 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).
+ * </pre>
+ */
+ 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 <i>MAC</i> algorithm.
+ *
+ * @return the output length in bytes of this <i>MAC</i> 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 <i>MAC</i> operation using the input byte.
+ *
+ * @param b the input byte to digest.
+ */
+ void update(byte b);
+
+ /**
+ * Continues a <i>MAC</i> 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 <i>MAC</i> by performing final operations such as padding
+ * and resetting the instance.
+ *
+ * @return the array of bytes representing the <i>MAC</i> 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 <code>true</code> if the implementation passes a basic self-test.
+ * Returns <code>false</code> 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 <i>Factory</i> that instantiates instances of every supported Message
+ * Authentication Code algorithms, including all <i>HMAC</i> algorithms.
+ */
+public class MacFactory
+ implements Registry
+{
+ private static Set names;
+
+ /** Trivial constructor to enforce <i>Singleton</i> pattern. */
+ private MacFactory()
+ {
+ super();
+ }
+
+ /**
+ * Returns an instance of a <i>MAC</i> algorithm given its name.
+ *
+ * @param name the name of the MAC algorithm.
+ * @return an instance of the <i>MAC</i> algorithm, or <code>null</code> 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 <i>MAC</i> algorithms supported by this
+ * <i>Factory</i>.
+ *
+ * @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 <i>mac</i> argument must have already been initialized, and
+ * the <i>mac</i> argument is <b>not</b> 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 <code>MacOutputStream</code>. The stream is initially set
+ * to digest data written, the <code>mac</code> argument must have already
+ * been initialized, and the <code>mac</code> argument is <b>not</b>
+ * 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li>Tetsu Iwata and Kaoru Kurosawa, <i><a
+ * href="http://crypt.cis.ibaraki.ac.jp/omac/docs/omac.pdf">OMAC: One-Key CBC
+ * MAC</a></i>.</li>
+ * </ol>
+ */
+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;
+
+/**
+ * <i>TMMH</i> is a <i>universal</i> 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.
+ * <p>
+ * <i>TMMH</i> 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. <i>TMMH</i>
+ * can be used as a message authentication code, as described in Section 5 (see
+ * References).
+ * <p>
+ * The key, message, and hash value are all octet strings, and the lengths of
+ * these quantities are denoted as <code>KEY_LENGTH</code>,
+ * <code>MESSAGE_LENGTH</code>, and <code>TAG_LENGTH</code>, respectively.
+ * The values of <code>KEY_LENGTH</code> and <code>TAG_LENGTH</code>
+ * <bold>MUST</bold> be fixed for any particular fixed value of the key, and
+ * must obey the alignment restrictions described below.
+ * <p>
+ * The parameter <code>MAX_HASH_LENGTH</code>, which denotes the maximum
+ * value which <code>MESSAGE_LENGTH</code> may take, is equal to
+ * <code>KEY_LENGTH - TAG_LENGTH</code>.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-mcgrew-saag-tmmh-01.txt"> The
+ * Truncated Multi-Modular Hash Function (TMMH)</a>, David A. McGrew.</li>
+ * </ol>
+ */
+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 <code>b</code> to start considering
+ * the bytes to process.
+ * @param len the number of bytes in <code>b</code> starting from
+ * <code>offset</code> 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;
+
+/**
+ * <i>UHASH</i> 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.
+ * <p>
+ * <i>UHASH</i> has been shown to be <i>epsilon-ASU</i> ("Almost Strongly
+ * Universal"), where epsilon is a small (parameter-dependent) real number.
+ * Informally, saying that a keyed hash function is <i>epsilon-ASU</i> 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.
+ * <p>
+ * <i>UHASH</i> has been designed to be fast by exploiting several
+ * architectural features of modern commodity processors. It was specifically
+ * designed for use in <i>UMAC</i>. But <i>UHASH</i> is useful beyond that
+ * domain, and can be easily adopted for other purposes.
+ * <p>
+ * <i>UHASH</i> does its work in three layers. First, a hash function called
+ * <code>NH</code> 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 <i>polynomial hash function</i> into a
+ * fixed-length 16-byte string. Finally, the 16-byte string is hashed using an
+ * <i>inner-product hash</i> 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">
+ * UMAC</a>: Message Authentication Code using Universal Hashing.<br>
+ * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li>
+ * </ol>
+ */
+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:
+ * <pre>
+ * +-----+--------------------+---------------------------------------+
+ * | 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 |
+ * +-----+--------------------+---------------------------------------+
+ *</pre>
+ *
+ * @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.
+ * <p>
+ * 5.4 L2-HASH-32: Second-layer hash.
+ * <ul>
+ * <li>Input:<br>
+ * K string of length 24 bytes.<br>
+ * M string of length less than 2^64 bytes.</li>
+ * <li>Returns:<br>
+ * Y, string of length 16 bytes.</li>
+ * </ul>
+ */
+ 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.
+ * <ul>
+ * <li>Input:<br/>
+ * K1 string of length 64 bytes.<br/>
+ * K2 string of length 4 bytes.<br/>
+ * M string of length 16 bytes.</li>
+ * <li>Returns:<br/>
+ * Y, string of length 4 bytes.</li>
+ * </ul>
+ */
+ 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 <i>UMAC</i> (Universal Message Authentication
+ * Code).
+ * <p>
+ * The <i>UMAC</i> algorithms described are <i>parameterized</i>. 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 <i>UMAC</i> (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
+ * <i>UMAC16</i> and <i>UMAC32</i>. The parameter sets have been chosen based
+ * on experimentation and provide good performance on a wide variety of
+ * processors. <i>UMAC16</i> 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 <i>UMAC32</i> is designed to do well on
+ * processors with good 32- and 64- bit support. <i>UMAC32</i> may take
+ * advantage of SIMD parallelism in future processors.
+ * <p>
+ * <i>UMAC</i> has been designed to allow implementations which accommodate
+ * <i>on-line</i> authentication. This means that pieces of the message may be
+ * presented to <i>UMAC</i> 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.
+ * <p>
+ * To authenticate a message, <code>Msg</code>, 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
+ * <pre>
+ * AuthTag = f(Nonce) xor h(Msg)
+ * </pre>
+ * <p>
+ * Here <code>f</code> 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 <i>UMAC</i>, a shared key is used to key the pseudorandom
+ * function <code>f</code>, and then <code>f</code> is used for both tag
+ * generation and internally to generate all of the bits needed by the universal
+ * hash function.
+ * <p>
+ * The universal hash function that we use is called <code>UHASH</code>. 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.
+ * <p>
+ * For the pseudorandom function we use the block cipher of the <i>Advanced
+ * Encryption Standard</i> (AES).
+ * <p>
+ * The UMAC32 parameters, considered in this implementation are:
+ * <pre>
+ * UMAC32
+ * ------
+ * WORD-LEN 4
+ * UMAC-OUTPUT-LEN 8
+ * L1-KEY-LEN 1024
+ * UMAC-KEY-LEN 16
+ * ENDIAN-FAVORITE BIG *
+ * L1-OPERATIONS-SIGN UNSIGNED
+ * </pre>
+ * <p>
+ * Please note that this UMAC32 differs from the one described in the paper by
+ * the <i>ENDIAN-FAVORITE</i> value.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">
+ * UMAC</a>: Message Authentication Code using Universal Hashing.<br>
+ * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li>
+ * </ol>
+ */
+public class UMac32
+ extends BaseMac
+{
+ /**
+ * Property name of the user-supplied <i>Nonce</i>. 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 <i>UMAC</i> instance consists of defining values for the
+ * following parameters:
+ * <ol>
+ * <li>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}.</li>
+ * <li>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).</li>
+ * </ol>
+ * <p>
+ * For convenience, this implementation accepts that not both parameters be
+ * always specified.
+ * <ul>
+ * <li>If the <i>Key Material</i> is specified, but the <i>Nonce Material</i>
+ * is not, then this implementation, re-uses the previously set <i>Nonce
+ * Material</i> after (a) converting the bytes to an unsigned integer, (b)
+ * incrementing the number by one, and (c) converting it back to 16 bytes.</li>
+ * <li>If the <i>Nonce Material</i> is specified, but the <i>Key Material</i>
+ * is not, then this implementation re-uses the previously set <i>Key Material</i>.
+ * </li>
+ * </ul>
+ * <p>
+ * This method throws an exception if no <i>Key Material</i> is specified in
+ * the input map, and there is no previously set/defined <i>Key Material</i>
+ * (from an earlier invocation of this method). If a <i>Key Material</i> can
+ * be used, but no <i>Nonce Material</i> 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
+ * <code>init()</code> methods, a <i>Mode</i> 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}.
+ * <p>
+ * 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:
+ *
+ * <pre>
+ * C<sub>i</sub> = E<sub>K</sub>(P<sub>i</sub>&circ; C<sub>i-1</sub>)
+ * </pre>
+ * <p>
+ * Similarly, decrypting is:
+ * <pre>
+ * P<sub>i</sub> = C<sub>i-1</sub> &circ; D<sub>K</sub>(C<sub>i</sub>)
+ * </pre>
+ */
+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 <i>s</i>
+ * bit blocks, where 1 &lt;= <i>s</i> &lt;= <i>b</i>, if <i>b</i> is the
+ * underlying cipher's block size. Encryption is:
+ * <pre>
+ * 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] &circ; MSB(s, O[j]) for j = 1,2...n
+ * </pre>
+ * <p>
+ * And decryption is:
+ * <pre>
+ * 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] &circ; MSB(s, O[j]) for j = 1,2...n
+ * </pre>
+ * <p>
+ * CFB mode requires an initialization vector, which need not be kept secret.
+ * <p>
+ * References:
+ * <ol>
+ * <li>Bruce Schneier, <i>Applied Cryptography: Protocols, Algorithms, and
+ * Source Code in C, Second Edition</i>. (1996 John Wiley and Sons) ISBN
+ * 0-471-11709-9.</li>
+ * <li><a
+ * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf">
+ * Recommendation for Block Cipher Modes of Operation Methods and Techniques</a>,
+ * Morris Dworkin.</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * The algorithm steps are formally described as follows:
+ *
+ * <pre>
+ * CTR Encryption: O[j] = E(K)(T[j]); for j = 1, 2...n;
+ * C[j] = P[j] &circ; O[j]; for j = 1, 2...n.
+ * CTR Decryption: O[j] = E(K)(T[j]); for j = 1, 2...n;
+ * P[j] = C[j] &circ; O[j]; for j = 1, 2...n.
+ * </pre>
+ *
+ * <p>
+ * where <code>P</code> is the plaintext, <code>C</code> is the ciphertext,
+ * <code>E(K)</code> is the underlying block cipher encryption function
+ * parametrised with the session key <code>K</code>, and <code>T</code> is
+ * the <i>Counter</i>.
+ * <p>
+ * This implementation, uses a standard incrementing function with a step of 1,
+ * and an initial value similar to that described in the NIST document.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf">
+ * Recommendation for Block Cipher Modes of Operation Methods and Techniques</a>,
+ * Morris Dworkin.</li>
+ * </ol>
+ */
+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
+ * <i>Authenticated Encryption with Additional Data</i> (<b>AEAD</b>) 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).
+ * <p>
+ * 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li>M. Bellare, P. Rogaway, and D. Wagner; <a
+ * href="http://www.cs.berkeley.edu/~daw/papers/eprint-short-ae.pdf">A
+ * Conventional Authenticated-Encryption Mode</a>.</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * The Electronic Codebook (ECB) mode is a confidentiality mode that is defined
+ * as follows:
+ * <ul>
+ * <li>ECB Encryption: C<sub>j</sub> = CIPH<sub>K</sub>(P<sub>j</sub>)
+ * for j = 1...n</li>
+ * <li>ECB Decryption: P<sub>j</sub> = CIPH<sup>-1</sup><sub>K</sub>(C<sub>j</sub>)
+ * for j = 1...n</li>
+ * </ul>
+ * <p>
+ * 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.
+ * <p>
+ * 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf">
+ * Recommendation for Block Cipher Modes of Operation Methods and Techniques</a>,
+ * Morris Dworkin.</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * 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 <i>David McGrew</i> Integer Counter Mode (ICM) as an
+ * {@link IMode}.
+ * <p>
+ * 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.
+ * <p>
+ * 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 <i>block index length</i> and the <i>segment
+ * index length</i>. A constraint on those two values exists: The sum of
+ * <i>segment index length</i> and <i>block index length</i> <b>must not</b>
+ * half the <i>block size</i> of the underlying cipher. This requirement
+ * protects the ICM keystream generator from potentially failing to be
+ * pseudorandom.
+ * <p>
+ * For simplicity, this implementation, fixes these two values to the following:
+ * <ul>
+ * <li>block index length: is half the underlying cipher block size, and</li>
+ * <li>segment index length: is zero.</li>
+ * </ul>
+ * <p>
+ * 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
+ * <code>(256 ^ <i>block index length</i>) * <i>block length</i></code>
+ * octets.
+ * <p>
+ * Finally, for this implementation of the ICM, the IV placeholder will be used
+ * to pass the value of the <i>Offset</i> in the keystream segment.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-mcgrew-saag-icm-00.txt">
+ * Integer Counter Mode</a>, David A. McGrew.</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * 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.
+ * <p>
+ * A <i>Mode</i> always employs an underlying block cipher for processing its
+ * input. For all intents and purposes, a <i>Mode</i> appears to behave as any
+ * other block cipher with the following differences:
+ * <ul>
+ * <li>Depending on the specifications of the mode, the block size may be
+ * different that that of the underlying cipher.</li>
+ * <li>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 <tt>byte</tt> is the smallest, easy to handle,
+ * primitive type in Java.</li>
+ * <li>Some modes need an <i>Initialisation Vector</i> (IV) to be properly
+ * initialised.</li>
+ * </ul>
+ * <p>
+ * Possible additional initialisation values for an instance of that type are:
+ * <ul>
+ * <li>The block size in which to operate this mode instance. This value is
+ * <b>optional</b>, if unspecified, the underlying block cipher's configured
+ * block size shall be used.</li>
+ * <li>Whether this mode will be used for encryption or decryption. This value
+ * is <b>mandatory</b> 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 <code>reset()</code> is invoked on the instance.</li>
+ * <li>The byte array containing the <i>initialisation vector</i>, if required
+ * by this type of mode.</li>
+ * </ul>
+ */
+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 <code>ENCRYPTION</code> or <code>DECRYPTION</code>.
+ */
+ 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 <i>encryption</i>. */
+ int ENCRYPTION = 1;
+ /** Constant indicating the instance is being used for <i>decryption</i>. */
+ int DECRYPTION = 2;
+
+ /**
+ * A convenience method. Effectively invokes the <code>encryptBlock()</code>
+ * or <code>decryptBlock()</code> method depending on the operational state
+ * of the instance.
+ *
+ * @param in the plaintext.
+ * @param inOffset index of <code>in</code> from which to start considering
+ * data.
+ * @param out the ciphertext.
+ * @param outOffset index of <code>out</code> 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 <i>Factory</i> 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 <code>null</code> 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 <i>Factory</i>.
+ *
+ * @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 <code>IV</code> for every message that is ever encrypted under the
+ * given key. The OFB mode is defined as follows:
+ * <ul>
+ * <li>OFB Encryption:
+ * <ul>
+ * <li>I<sub>1</sub> = IV;</li>
+ * <li>I<sub>j</sub> = O<sub>j -1</sub> for j = 2...n;</li>
+ * <li>O<sub>j</sub> = CIPH<sub>K</sub>(I<sub>j</sub>) for j = 1, 2...n;</li>
+ * <li>C<sub>j</sub> = P<sub>j</sub> XOR O<sub>j</sub> for j = 1, 2...n.</li>
+ * </ul>
+ * </li>
+ * <li>OFB Decryption:
+ * <ul>
+ * <li>I<sub>1</sub> = IV;</li>
+ * <li>I<sub>j</sub> = O<sub>j -1</sub> for j = 2...n;</li>
+ * <li>O<sub>j</sub> = CIPH<sub>K</sub>(I<sub>j</sub>) for j = 1, 2...n;</li>
+ * <li>P<sub>j</sub> = C<sub>j</sub> XOR O<sub>j</sub> for j = 1, 2...n.</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * <p>
+ * In OFB encryption, the <code>IV</code> 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.
+ * <p>
+ * In OFB decryption, the <code>IV</code> 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.
+ * <p>
+ * 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 <code>IV</code> is known, the output blocks can
+ * be generated prior to the availability of the plaintext or ciphertext data.
+ * <p>
+ * The OFB mode requires a unique <code>IV</code> for every message that is
+ * ever encrypted under the given key. If, contrary to this requirement, the
+ * same <code>IV</code> 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 j<sup>th</sup>
+ * plaintext block, then the j<sup>th</sup> output of the forward cipher
+ * function can be determined easily from the j<sup>th</sup> ciphertext block
+ * of the message. This information allows the j<sup>th</sup> plaintext block
+ * of any other message that is encrypted using the same <code>IV</code> to be
+ * easily recovered from the jth ciphertext block of that message.
+ * <p>
+ * 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
+ * <code>IV</code> for the encryption of another message under the given key.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf">
+ * Recommendation for Block Cipher Modes of Operation Methods and Techniques</a>,
+ * Morris Dworkin.</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * For compatibility reasons, this method is not declared <i>abstract</i>.
+ * 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 <code>true</code> if the concrete implementation correctly unpads
+ * what it pads for all tested block sizes. Returns <code>false</code>
+ * 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.
+ * <p>
+ * 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 <code>true</code> if the test passes; <code>false</code>
+ * 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.
+ * <p>
+ * Padding algorithms serve to <i>pad</i> and <i>unpad</i> byte arrays usually
+ * as the last step in an <i>encryption</i> or respectively a <i>decryption</i>
+ * 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 <i>in</i>.
+ * @param length the number of meaningful bytes in <i>in</i>.
+ * @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 <i>in</i>.
+ * @param length the number of meaningful bytes in <i>in</i>.
+ * @return the number of bytes to discard, to the left of index position
+ * <code>offset + length</code> in <i>in</i>. In other words, if
+ * the return value of a successful invocation of this method is
+ * <code>result</code>, then the unpadded byte sequence will be
+ * <code>offset + length - result</code> bytes in <i>in</i>,
+ * starting from index position <code>offset</code>.
+ * @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 <code>true</code> if the implementation passes a basic symmetric
+ * self-test. Returns <code>false</code> 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.
+ * <p>
+ * The last byte of the padding block is the number of padding bytes, all other
+ * padding bytes are random.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.w3.org/TR/xmlenc-core/">XML Encryption Syntax and
+ * Processing</a> Section "5.2 Block Encryption Algorithms"; "Padding".</li>
+ * </ol>
+ */
+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
+ * <i>Adapter</i> over an instance of {@link EME_PKCS1_V1_5} initialised with
+ * the RSA public shared modulus length (in bytes).
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc3447.txt">Public-Key Cryptography
+ * Standards (PKCS) #1:</a><br>
+ * RSA Cryptography Specifications Version 2.1.<br>
+ * Jakob Jonsson and Burt Kaliski.</li>
+ * </ol>
+ *
+ * @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 <i>Factory</i> 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.
+ * <p>
+ * This algorithm is described for 8-byte blocks in [RFC-1423] and extended to
+ * block sizes of up to 256 bytes in [PKCS-7].
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/rfc/rfc1423.txt">RFC-1423</a>: Privacy
+ * Enhancement for Internet Electronic Mail: Part III: Algorithms, Modes, and
+ * Identifiers.</li>
+ * <li><a href="http://www.ietf.org/">IETF</a>.</li>
+ * <li><a href="http://www.rsasecurity.com/rsalabs/pkcs/pkcs-7/">[PKCS-7]</a>
+ * PKCS #7: Cryptographic Message Syntax Standard - An RSA Laboratories
+ * Technical Note.</li>
+ * <li><a href="http://www.rsasecurity.com/">RSA Security</a>.</li>
+ * </ol>
+ */
+public final class PKCS7
+ extends BasePad
+{
+ private static final Logger log = Logger.getLogger(PKCS7.class.getName());
+
+ /**
+ * Trivial package-private constructor for use by the <i>Factory</i> 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 <code>null</code> 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
+ * <i>Factory</i>.
+ *
+ * @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.:
+ * <pre>
+ * block-ciphered struct {
+ * opaque content[SSLCompressed.length];
+ * opaque MAC[CipherSpec.hash_size];
+ * uint8 padding[GenericBlockCipher.padding_length];
+ * uint8 padding_length;
+ * } GenericBlockCipher;
+ * </pre>
+ * <p>
+ * Where <i>padding_length</i> is <i>cipher_block_size</i> -
+ * ((<i>SSLCompressed.length</i> + <i>CipherSpec.hash_size</i>) %
+ * <i>cipher_block_size</i>) - 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.
+ * <p>
+ * 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 <tt>1</tt>, then <tt>0</tt> bits are appended, and if the trailing
+ * bit is <tt>0</tt>, then <tt>1</tt> bits are appended. As few bits are
+ * added as are necessary to meet the formatting size requirement."
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://csrc.nist.gov/encryption/modes/Recommendation/Modes01.pdf">
+ * Recommendation for Block Cipher Modes of Operation Methods and
+ * Techniques</a>, Morris Dworkin.</li>
+ * </ol>
+ */
+public final class TBC
+ extends BasePad
+{
+ private static final Logger log = Logger.getLogger(TBC.class.getName());
+
+ /**
+ * Trivial package-private constructor for use by the <i>Factory</i> 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.:
+ * <pre>
+ * block-ciphered struct {
+ * opaque content[TLSCompressed.length];
+ * opaque MAC[CipherSpec.hash_size];
+ * uint8 padding[GenericBlockCipher.padding_length];
+ * uint8 padding_length;
+ * } GenericBlockCipher;
+ * </pre>
+ * <p>
+ * Where <i>padding_length</i> is any multiple of <i>cipher_block_size</i> -
+ * ((<i>SSLCompressed.length</i> + <i>CipherSpec.hash_size</i>) %
+ * <i>cipher_block_size</i>) - 1 that is less than 255. Every byte of the
+ * padding must be equal to <i>padding_length</i>. That is, the end of the
+ * plaintext is <i>n</i> + 1 copies of the unsigned byte <i>n</i>.
+ */
+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".
+ * <p>
+ * This class only implements the <i>keystream</i> of ARCFOUR. To use this as a
+ * stream cipher, one would say:
+ * <pre>
+ * out = in &circ; arcfour.nextByte();
+ * </pre>
+ * <p>
+ * This operation works for encryption and decryption.
+ * <p>
+ * References:
+ * <ol>
+ * <li>Schneier, Bruce: <i>Applied Cryptography: Protocols, Algorithms, and
+ * Source Code in C, Second Edition.</i> (1996 John Wiley and Sons), pp.
+ * 397--398. ISBN 0-471-11709-9</li>
+ * <li>K. Kaukonen and R. Thayer, "A Stream Cipher Encryption Algorithm
+ * 'Arcfour'", Internet Draft (expired), <a
+ * href="http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt">draft-kaukonen-cipher-arcfour-03.txt</a></li>
+ * </ol>
+ */
+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 (<a
+ * href="http://www.cs.auckland.ac.nz/~pgut001/cryptlib/">http://www.cs.auckland.ac.nz/~pgut001/cryptlib/</a>).
+ * <p>
+ * The basic properties of this generator are:
+ * <ol>
+ * <li>The internal state cannot be determined by knowledge of the input.</li>
+ * <li>It is resistant to bias introduced by specific inputs.</li>
+ * <li>The output does not reveal the state of the generator.</li>
+ * </ol>
+ */
+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:
+ * <ol>
+ * <li>A {@link Double}, indicating the suggested <i>quality</i> of this
+ * source. This value must be between 0 and 100.</li>
+ * <li>An {@link Integer}, indicating the number of bytes to skip in the
+ * file before reading bytes. This can be any nonnegative value.</li>
+ * <li>An {@link Integer}, indicating the number of bytes to read.</li>
+ * <li>A {@link String}, indicating the path to the file.</li>
+ * </ol>
+ *
+ * @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}.
+ * <p>
+ * All properties are of the from <i>name</i>.</i>N</i>, where <i>name</i>
+ * is the name of the source, and <i>N</i> is an integer (staring at 1) that
+ * indicates the preference number for that source.
+ * <p>
+ * The following vales for <i>name</i> are used here:
+ * <dl>
+ * <dt>gnu.crypto.csprng.file</dt>
+ * <dd>
+ * <p>
+ * These properties are file sources, passed as the {@link #FILE_SOURCES}
+ * parameter of the instance. The property value is a 4-tuple formatted as:
+ * </p>
+ * <blockquote><i>quality</i> ; <i>offset</i> ; <i>count</i> ; <i>path</i></blockquote>
+ * <p>
+ * The parameters are mapped to the parameters defined for {@link
+ * #FILE_SOURCES}. Leading or trailing spaces on any item are trimmed off.
+ * </p>
+ * </dd>
+ * <dt>gnu.crypto.csprng.url</dt>
+ * <dd>
+ * <p>
+ * 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 <i>path</i> argument must be a valid URL.
+ * </p>
+ * </dd>
+ * <dt>gnu.crypto.csprng.program</dt>
+ * <dd>
+ * <p>
+ * 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.
+ * </p>
+ * </dd>
+ * <dt>gnu.crypto.cspring.other</dt>
+ * <dd>
+ * <p>
+ * 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.
+ * </p>
+ * </dd>
+ * </dl>
+ * <p>
+ * Finally, a boolean property "gnu.crypto.csprng.blocking" can be set to the
+ * desired value of {@link #BLOCKING}.
+ * <p>
+ * An example of valid properties would be:
+ * <pre>
+ * 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
+ * </pre>
+ */
+ 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
+ * <i>not</i> 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 <i>off</i> or <i>len</i> are
+ * out of the range of <i>buf</i>.
+ */
+ 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
+ * <i>not</i> 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.
+ * <p>
+ * 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.
+ * <p>
+ * There are some things users of this class <em>must</em> be aware of:
+ * <dl>
+ * <dt>Adding Random Data</dt>
+ * <dd>This class does not do any polling of random sources, but rather
+ * provides an interface for adding random events. Applications that use this
+ * code <em>must</em> 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.</dd>
+ * <dt>Storing the Seed</dt>
+ * <dd>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.</dd>
+ * </dl>
+ * <p>
+ * <b>References:</b>
+ * <ul>
+ * <li>Niels Ferguson and Bruce Schneier, <i>Practical Cryptography</i>, pp.
+ * 155--184. Wiley Publishing, Indianapolis. (2003 Niels Ferguson and Bruce
+ * Schneier). ISBN 0-471-22357-3.</li>
+ * </ul>
+ */
+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.
+ * <p>
+ * 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.
+ * <p>
+ * This implementation adheres to the definition of the ICM keystream generation
+ * function that allows for any symetric key block cipher algorithm
+ * (initialisation parameter <code>gnu.crypto.prng.icm.cipher.name</code>
+ * taken to be an instance of {@link java.lang.String}) to be used. If such a
+ * parameter is not defined/included in the initialisation <code>Map</code>,
+ * then the "Rijndael" algorithm is used. Furthermore, if the initialisation
+ * parameter <code>gnu.crypto.cipher.block.size</code> (taken to be a instance
+ * of {@link java.lang.Integer}) is missing or undefined in the initialisation
+ * <code>Map</code>, then the cipher's <em>default</em> block size is used.
+ * <p>
+ * The practical limits and constraints of such generator are:
+ * <ul>
+ * <li>The number of blocks in any segment <b>MUST NOT</b> exceed <code>
+ * 256 ** BLOCK_INDEX_LENGTH</code>.
+ * The number of segments <b>MUST NOT</b> exceed
+ * <code>256 ** SEGMENT_INDEX_LENGTH</code>. These restrictions ensure the
+ * uniqueness of each block cipher input.</li>
+ * <li>Each segment contains <code>SEGMENT_LENGTH</code> octets; this value
+ * <b>MUST NOT</b> exceed the value <code>(256 ** BLOCK_INDEX_LENGTH) *
+ * BLOCK_LENGTH</code>.</li>
+ * <li>The sum of <code>SEGMENT_INDEX_LENGTH</code> and
+ * <code>BLOCK_INDEX_LENGTH</code> <b>MUST NOT</b> exceed <code>BLOCK_LENGTH
+ * / 2</code>.
+ * This requirement protects the ICM keystream generator from potentially
+ * failing to be pseudorandom.</li>
+ * </ul>
+ * <p>
+ * <b>NOTE</b>: 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 <em>longer</em> key streams.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-mcgrew-saag-icm-00.txt">
+ * Integer Counter Mode</a>, David A. McGrew.</li>
+ * </ol>
+ */
+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 <i>key derivation function</i> KDF2 from PKCS #5:
+ * Password-Based Cryptography (<b>PBE</b>). 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.
+ * <p>
+ * This version uses a MAC as its pseudo-random function, and the password is
+ * used as the key.
+ * <p>
+ * References:
+ * <ol>
+ * <li>B. Kaliski, <a href="http://www.ietf.org/rfc/rfc2898.txt">RFC 2898:
+ * Password-Based Cryptography Specification, Version 2.0</a></li>
+ * </ol>
+ */
+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 <i>Singleton</i> 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
+ * <i>Factory</i>.
+ *
+ * @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;
+
+/**
+ * <i>KDF</i>s (Key Derivation Functions) are used to stretch user-supplied key
+ * material to specific size(s) required by high level cryptographic primitives.
+ * Described in the <A
+ * HREF="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">UMAC</A>
+ * paper, this function basically operates an underlying <em>symmetric key block
+ * cipher</em> instance in output feedback mode (OFB), as a <b>strong</b>
+ * pseudo-random number generator.
+ * <p>
+ * <code>UMacGenerator</code> requires an <em>index</em> parameter
+ * (initialisation parameter <code>gnu.crypto.prng.umac.kdf.index</code> taken
+ * to be an instance of {@link Integer} with a value between <code>0</code> and
+ * <code>255</code>). Using the same key, but different indices, generates
+ * different pseudorandom outputs.
+ * <p>
+ * This implementation generalises the definition of the
+ * <code>UmacGenerator</code> algorithm to allow for other than the AES
+ * symetric key block cipher algorithm (initialisation parameter
+ * <code>gnu.crypto.prng.umac.cipher.name</code> taken to be an instance of
+ * {@link String}). If such a parameter is not defined/included in the
+ * initialisation <code>Map</code>, then the "Rijndael" algorithm is used.
+ * Furthermore, if the initialisation parameter
+ * <code>gnu.crypto.cipher.block.size</code> (taken to be a instance of
+ * {@link Integer}) is missing or undefined in the initialisation
+ * <code>Map</code>, then the cipher's <em>default</em> block size is used.
+ * <p>
+ * <b>NOTE</b>: 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.
+ * <p>
+ * References:
+ * <ol>
+ * <li><a href="http://www.ietf.org/internet-drafts/draft-krovetz-umac-01.txt">
+ * UMAC</a>: Message Authentication Code using Universal Hashing.<br>
+ * T. Krovetz, J. Black, S. Halevi, A. Hevia, H. Krawczyk, and P. Rogaway.</li>
+ * </ol>
+ */
+public class UMacGenerator
+ extends BasePRNG
+ implements Cloneable
+{
+ /**
+ * Property name of the KDF <code>index</code> value to use in this
+ * instance. The value is taken to be an {@link Integer} less than
+ * <code>256</code>.
+ */
+ 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
+ * <code>gnu.crypto.sasl.auth.info.provider.pkgs</code>. 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 <code>null</code> 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 <i>confidentiality</i> protection filter.
+ */
+public class ConfidentialityException
+ extends SaslException
+{
+ /**
+ * Constructs a new instance of <code>ConfidentialityException</code> with
+ * no detail message.
+ */
+ public ConfidentialityException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a new instance of <code>ConfidentialityException</code> with
+ * the specified detail message.
+ *
+ * @param s the detail message.
+ */
+ public ConfidentialityException(String s)
+ {
+ super(s);
+ }
+
+ /**
+ * Constructs a new instance of <code>ConfidentialityException</code> 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 <i>activated</i> 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 <code>true</code> if the user with the designated name is known
+ * to this provider; <code>false</code> 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 <code>null</code> 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 <code>IllegalMechanismStateException</code>
+ * with no detail message.
+ */
+ public IllegalMechanismStateException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a new instance of <code>IllegalMechanismStateException</code>
+ * with the specified detail message.
+ *
+ * @param detail the detail message.
+ */
+ public IllegalMechanismStateException(String detail)
+ {
+ super(detail);
+ }
+
+ /**
+ * Constructs a new instance of <code>IllegalMechanismStateException</code>
+ * 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.
+ * <p>
+ * The data elements this class caters for are described in [1].
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
+ * Secure Remote Password Authentication Mechanism</a>;<br/>
+ * draft-burdis-cat-srp-sasl-09,<br/> <a
+ * href="mailto:keith@rucus.ru.ac.za">Keith Burdis</a> and <a
+ * href="mailto:raif@forge.com.au">Ra&iuml;f S. Naffah</a>.</li>
+ * </ol>
+ */
+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.
+ * <p>
+ * Calls the method with the same name and three arguments as:
+ * <code>getInstance(raw, 0, raw.length)</code>.
+ *
+ * @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, <code>count</code>-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 <i>integrity</i> protection filter, including <i>replay
+ * detection</i>.
+ */
+public class IntegrityException
+ extends SaslException
+{
+ /**
+ * Constructs a new instance of <code>IntegrityException</code> with no
+ * detail message.
+ */
+ public IntegrityException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a new instance of <code>IntegrityException</code> with the
+ * specified detail message.
+ *
+ * @param s the detail message.
+ */
+ public IntegrityException(String s)
+ {
+ super(s);
+ }
+
+ /**
+ * Constructs a new instance of <code>IntegrityException</code> 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 <code>NoSuchMechanismException</code> 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 <code>NoSuchUserException</code> with no detail message. */
+ public NoSuchUserException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a <code>NoSuchUserException</code> 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.
+ * <p>
+ * The data elements this class caters for are described in [1].
+ * <p>
+ * References:
+ * <ol>
+ * <li><a
+ * href="http://www.ietf.org/internet-drafts/draft-burdis-cat-srp-sasl-09.txt">
+ * Secure Remote Password Authentication Mechanism</a>;<br/>
+ * draft-burdis-cat-srp-sasl-09,<br/> <a
+ * href="mailto:keith@rucus.ru.ac.za">Keith Burdis</a> and <a
+ * href="mailto:raif@forge.com.au">Ra&iuml;f S. Naffah</a>.</li>
+ * </ol>
+ */
+public class OutputBuffer
+{
+ /** The internal output stream. */
+ private ByteArrayOutputStream out;
+
+ public OutputBuffer()
+ {
+ super();
+
+ out = new ByteArrayOutputStream();
+ }
+
+ /**
+ * Encodes a SASL scalar quantity, <code>count</code>-octet long, to the
+ * current buffer.
+ *
+ * @param count number of octets to encode <code>b</code> 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 <code>SaslEncodingException</code> with no detail message. */
+ public SaslEncodingException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a <code>SaslEncodingException</code> 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 <code>int</code> in the range <code>0</code> to
+ * <code>255</code>. If no byte is available because the end of the stream
+ * has been reached, the value <code>-1</code> is returned. This method
+ * blocks until input data is available, the end of the stream is detected, or
+ * an exception is thrown.
+ * <p>
+ * From a SASL mechanism provider's perspective, if a security layer has been
+ * negotiated, the underlying <i>source</i> 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 <code>-1</code> 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 <code>len</code> bytes of data from the underlying <i>source</i>
+ * input stream into an array of bytes. An attempt is made to read as many as
+ * <code>len</code> bytes, but a smaller number may be read, possibly zero.
+ * The number of bytes actually read is returned as an integer.
+ * <p>
+ * This method blocks until input data is available, end of file is detected,
+ * or an exception is thrown.
+ * <p>
+ * If <code>b</code> is <code>null</code>, a {@link NullPointerException}
+ * is thrown.
+ * <p>
+ * If <code>off</code> is negative, or <code>len</code> is negative, or
+ * <code>off+len</code> is greater than the length of the array
+ * <code>b</code>, then an {@link IndexOutOfBoundsException} is thrown.
+ * <p>
+ * If <code>len</code> is zero, then no bytes are read and <code>0</code>
+ * 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
+ * <code>-1</code> is returned; otherwise, at least one byte is read and
+ * stored into <code>b</code>.
+ * <p>
+ * The first byte read is stored into element <code>b[off]</code>, the next
+ * one into <code>b[off+1]</code>, and so on. The number of bytes read is,
+ * at most, equal to <code>len</code>. Let <code>k</code> be the number
+ * of bytes actually read; these bytes will be stored in elements
+ * <code>b[off]</code> through <code>b[off+k-1]</code>, leaving elements
+ * <code>b[off+k]</code> through <code>b[off+len-1]</code> unaffected.
+ * <p>
+ * In every case, elements <code>b[0]</code> through <code>b[off]</code>
+ * and elements <code>b[off+len]</code> through <code>b[b.length-1]</code>
+ * are unaffected.
+ * <p>
+ * 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.
+ * <p>
+ * From the SASL mechanism provider's perspective, if a security layer has
+ * been negotiated, the underlying <i>source</i> 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 <code>b</code> 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 <code>-1</code>
+ * 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
+ * <code>write()</code>) will be encapsulated as a SASL buffer, as defined in
+ * RFC 2222, and then written to the underlying <i>dest</i> 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
+ * <code>write()</code>) will be encapsulated as a SASL buffer, as defined in
+ * RFC 2222, and then written to the underlying <i>dest</i> 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 <code>UserAlreadyExistsException</code> with no detail
+ * message.
+ */
+ public UserAlreadyExistsException()
+ {
+ super();
+ }
+
+ /**
+ * Constructs a <code>UserAlreadyExistsException</code> 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.
+ * <p>
+ * The designated CALG block cipher should be used in OFB (Output Feedback
+ * Block) mode in the ISO variant, as described in <i>The Handbook of Applied
+ * Cryptography</i>, algorithm 7.20.
+ * <p>
+ * Let <code>k</code> be the block size of the chosen symmetric key block
+ * cipher algorithm; e.g. for AES this is <code>128</code> bits or
+ * <code>16</code> octets. The OFB mode used shall be of length/size
+ * <code>k</code>.
+ * <p>
+ * 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 <code>k</code> bytes.
+ * <p>
+ * The input data to the confidentiality protection algorithm shall be a
+ * multiple of the symmetric cipher block size <code>k</code>. When the input
+ * length is not a multiple of <code>k</code> octets, the data shall be padded
+ * according to the following scheme:
+ * <p>
+ * Assuming the length of the input is <code>l</code> octets,
+ * <code>(k - (l mod k))</code> octets, all having the value
+ * <code>(k - (l mod k))</code>, shall be appended to the original data. In
+ * other words, the input is padded at the trailing end with one of the
+ * following sequences:
+ * <pre>
+ *
+ * 01 -- if l mod k = k-1
+ * 02 02 -- if l mod k = k-2
+ * ...
+ * ...
+ * ...
+ * k k ... k k -- if l mod k = 0
+ * </pre>
+ * <p>
+ * 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 <code>k &lt; 256</code> 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 <code>data</code>.
+ * @param length how many bytes to consider in <code>data</code>.
+ * @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 <code>true</code> if the designated client's session is still
+ * alive. <code>false</code> 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 <code>KDF</code> 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 <code>KDF</code> based on
+ * supplied seed data.
+ *
+ * @param K the SASL SRP shared secret for a <code>KDF</code> to be used for
+ * <i>CALG</i> and <i>IALG</i> setup. <code>null</code> otherwise.
+ * @return an instance of a <code>KDF</code>.
+ */
+ 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.
+ * <p>
+ * For SRP, there are three (3) files:
+ * <ol>
+ * <li>The password configuration file: tpasswd.conf. It contains the pairs
+ * &lt;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.</li>
+ * <li>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).</li>
+ * <li>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.</li>
+ * </ol>
+ * <p>
+ * This implementation assumes the following message digest algorithm codes:
+ * <ul>
+ * <li>0: the default hash algorithm, which is SHA-1 (or its alias SHA-160).</li>
+ * <li>1: MD5.</li>
+ * <li>2: RIPEMD-128.</li>
+ * <li>3: RIPEMD-160.</li>
+ * <li>4: SHA-256.</li>
+ * <li>5: SHA-384.</li>
+ * <li>6: SHA-512.</li>
+ * </ul>
+ * <p>
+ * <b>IMPORTANT:</b> This method computes the verifiers as described in
+ * RFC-2945, which differs from the description given on the web page for SRP-6.
+ * <p>
+ * Reference:
+ * <ol>
+ * <li><a href="http://srp.stanford.edu/design.html">SRP Protocol Design</a><br>
+ * Thomas J. Wu.</li>
+ * </ol>
+ */
+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 &lt;N, g> pair for
+ * the designated <code>index</code>.
+ *
+ * @param index a string representing 1-digit identification of an &lt;N, g>
+ * pair used.
+ * @return <code>true</code> if the designated <code>index</code> is that
+ * of a known &lt;N, g> pair, and <code>false</code> 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 <code>N</code> and
+ * <code>g</code> MPIs for the designated <code>index</code>.
+ *
+ * @param index a string representing 1-digit identification of an &lt;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 <code>N</code>, and
+ * the second (at index position #1) is the representation of the MPI
+ * <code>g</code>. If the <code>index</code> 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.
+ * <p>
+ * <b>IMPORTANT:</b> 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 &lt;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 <b>first</b> 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 <code>true</code> if the designated session is still alive.
+ * <code>false</code> 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 <code>true</code> if the Time-To_live period has not elapsed.
+ *
+ * @return <code>true</code> if the Time-To-Live period (in seconds) has not
+ * elapsed yet; <code>false</code> 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<N;i++){
+ byte[] RGBquad = new byte[4];
+ if(in.read(RGBquad) != 4)
+ throw new IOException("Error reading palette information.");
+ // RGBQUAD structure is b,g,r,0
+ r[i] = RGBquad[2];
+ g[i] = RGBquad[1];
+ b[i] = RGBquad[0];
+ }
+
+ offset += 4*N;
+ return new IndexColorModel(8, N, r, g, b);
+ }
+
+ /**
+ * Read bytes to the start of the image data
+ */
+ protected void skipToImage(ImageInputStream in) throws IOException {
+ byte[] d = new byte[1];
+ long n = fileHeader.getOffset() - offset;
+ for(int i=0;i<n;i++)
+ in.read(d);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/imageio/bmp/BMPEncoder.java b/libjava/classpath/gnu/javax/imageio/bmp/BMPEncoder.java
new file mode 100644
index 000000000..d7c54c0d6
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/BMPEncoder.java
@@ -0,0 +1,119 @@
+/* BMPEncoder.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.io.IOException;
+
+import javax.imageio.IIOImage;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.stream.ImageOutputStream;
+
+public abstract class BMPEncoder
+{
+
+ /**
+ * Constructs a new BMPEncoder.
+ */
+ public BMPEncoder()
+ {
+ // Nothing to do here.
+ }
+
+ /**
+ * Determines the coding type of the bitmap and returns the corresponding
+ * encoder.
+ *
+ * @param fh - the file header
+ * @param ih - the info header
+ * @return the appropriate encoder
+ */
+ public static BMPEncoder getEncoder(BMPFileHeader fh, BMPInfoHeader ih)
+ {
+ switch (ih.getCompression())
+ {
+ case BMPInfoHeader.BI_RGB:
+ switch (ih.getBitCount())
+ {
+ case 32:
+ return new EncodeRGB32(fh, ih);
+
+ case 24:
+ return new EncodeRGB24(fh, ih);
+
+ case 16:
+ return new EncodeRGB16(fh, ih);
+
+ case 8:
+ return new EncodeRGB8(fh, ih);
+
+ case 4:
+ return new EncodeRGB4(fh, ih);
+
+ case 1:
+ return new EncodeRGB1(fh, ih);
+
+ default:
+ return null;
+ }
+ case BMPInfoHeader.BI_RLE4:
+ return new EncodeRLE4(fh, ih);
+
+ case BMPInfoHeader.BI_RLE8:
+ return new EncodeRLE8(fh, ih);
+ default:
+ return null;
+ }
+ }
+
+ /**
+ * 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, metadata and
+ * thumbnails to be written
+ * @param param - image writing parameters, or null
+ * @exception IOException if a write error occurs
+ */
+ public abstract void encode(ImageOutputStream o, IIOMetadata streamMetadata,
+ IIOImage image, ImageWriteParam param)
+ throws IOException;
+}
diff --git a/libjava/classpath/gnu/javax/imageio/bmp/BMPException.java b/libjava/classpath/gnu/javax/imageio/bmp/BMPException.java
new file mode 100644
index 000000000..0ba3c6c74
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/BMPException.java
@@ -0,0 +1,47 @@
+/* BMPException.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you 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 javax.imageio.IIOException;
+
+public class BMPException extends IIOException {
+
+ public BMPException(String message){
+ super(message);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/imageio/bmp/BMPFileHeader.java b/libjava/classpath/gnu/javax/imageio/bmp/BMPFileHeader.java
new file mode 100644
index 000000000..0cfd72323
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/BMPFileHeader.java
@@ -0,0 +1,151 @@
+/* BMPFileHeader.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you 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.RenderedImage;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import javax.imageio.IIOImage;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.ImageOutputStream;
+
+public class BMPFileHeader {
+ /** Header signature, always 'BM' */
+ private final static short bfType = 0x424d;
+
+ /** Bitmap file size, in bytes. */
+ protected long bfSize;
+
+ /** Offset from the beginning of the file to the bitmap data */
+ protected long bfOffBits;
+
+ /** BITMAPFILEHEADER is 14 bytes */
+ public static final int SIZE = 14;
+ private static final int BITMAPINFOHEADER_SIZE = 40;
+
+ /**
+ * Creates the header from an input stream, which is not closed.
+ *
+ * @throws IOException if an I/O error occured.
+ * @throws BMPException if the header was invalid
+ */
+ public BMPFileHeader(ImageInputStream in) throws IOException, BMPException {
+ byte[] data = new byte[SIZE];
+
+ if (in.read(data) != SIZE)
+ throw new IOException("Couldn't read header.");
+ ByteBuffer buf = ByteBuffer.wrap(data);
+
+ if(buf.getShort(0) != bfType)
+ throw new BMPException("Not a BMP file.");
+
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+
+ // get size (keep unsigned)
+ bfSize = ((long)buf.getInt(2) & (0xFFFFFFFF));
+
+ // Two reserved shorts are here, and should be zero,
+ // perhaps they should be tested to be zero, but I don't
+ // feel this strictness is necessary.
+
+ bfOffBits = ((long)buf.getInt(10) & (0xFFFFFFFF));
+ }
+
+ /**
+ * Creates the header from an output stream, which is not closed.
+ *
+ * @param out - the image output stream
+ * @param im - the image
+ * @throws IOException if an I/O error occured.
+ */
+ public BMPFileHeader(ImageOutputStream out, IIOImage im) throws IOException
+ {
+ RenderedImage img = im.getRenderedImage();
+ int w = img.getWidth();
+ int h = img.getHeight();
+
+ bfOffBits = SIZE + BITMAPINFOHEADER_SIZE;
+ bfSize = ((w * h) * 3) + ((4 - ((w * 3) % 4)) * h) + bfOffBits;
+
+ write(out);
+ }
+
+ /**
+ * Writes the header to an output stream, which is not closed or flushed.
+ *
+ * @throws IOException if an I/O error occured.
+ */
+ public void write(ImageOutputStream out) throws IOException {
+ ByteBuffer buf = ByteBuffer.allocate(SIZE);
+ buf.putShort(0, bfType); // ID
+ buf.putInt(2, (int)(bfSize & (0xFFFFFFFF))); // size
+ buf.putInt(6, 0); // 4 reserved bytes set to zero
+ buf.putInt(7, (int)(bfOffBits & (0xFFFFFFFF))); // size
+ out.write(buf.array());
+ }
+
+ /**
+ * Sets the file size
+ */
+ public void setSize(long size){
+ bfSize = size;
+ }
+
+ /**
+ * Sets the bitmap offset within the file
+ */
+ public void setOffset(long offset){
+ bfOffBits = offset;
+ }
+
+ /**
+ * Gets the file size
+ */
+ public long getSize(){
+ return bfSize;
+ }
+
+ /**
+ * Gets the bitmap offset within the file
+ */
+ public long getOffset(){
+ return bfOffBits;
+ }
+}
diff --git a/libjava/classpath/gnu/javax/imageio/bmp/BMPImageReader.java b/libjava/classpath/gnu/javax/imageio/bmp/BMPImageReader.java
new file mode 100644
index 000000000..7b136bdf5
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/BMPImageReader.java
@@ -0,0 +1,148 @@
+/* BMPImageReader.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you 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.*;
+import javax.imageio.spi.*;
+import javax.imageio.metadata.*;
+import javax.imageio.stream.ImageInputStream;
+import java.util.Iterator;
+import java.awt.image.BufferedImage;
+
+public class BMPImageReader extends ImageReader {
+ private BMPInfoHeader infoHeader;
+ private BMPFileHeader fileHeader;
+ private BMPDecoder decoder;
+
+ protected BMPImageReader(ImageReaderSpi originatingProvider){
+ super(originatingProvider);
+ infoHeader = null;
+ fileHeader = null;
+ decoder = null;
+ }
+
+ private void validateIndex(int imageIndex)
+ throws IndexOutOfBoundsException {
+ if (imageIndex != 0)
+ 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))
+ throw new IllegalArgumentException("Input not an ImageInputStream.");
+ }
+
+ 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 readHeaders() throws IOException, IIOException {
+ if(fileHeader != null)
+ return;
+
+ checkStream();
+
+ fileHeader = new BMPFileHeader((ImageInputStream)input);
+ infoHeader = new BMPInfoHeader((ImageInputStream)input);
+ decoder = BMPDecoder.getDecoder(fileHeader, infoHeader);
+ }
+
+ public int getWidth(int imageIndex) throws IOException {
+ validateIndex(imageIndex);
+ readHeaders();
+ return infoHeader.getWidth();
+ }
+
+ public int getHeight(int imageIndex) throws IOException {
+ validateIndex(imageIndex);
+ readHeaders();
+ return infoHeader.getHeight();
+ }
+
+ public Iterator getImageTypes(int imageIndex){
+ validateIndex(imageIndex);
+ return null;
+ }
+
+ /**
+ * Returns the number of images. BMP files can only contain a single one.
+ */
+ public int getNumImages(boolean allowSearch){
+ return 1;
+ }
+
+
+ // 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);
+ readHeaders();
+ return decoder.decode((ImageInputStream)input);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/imageio/bmp/BMPImageReaderSpi.java b/libjava/classpath/gnu/javax/imageio/bmp/BMPImageReaderSpi.java
new file mode 100644
index 000000000..5d027963a
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/BMPImageReaderSpi.java
@@ -0,0 +1,116 @@
+/* BMPImageReaderSpi.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you 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 java.util.Locale;
+import javax.imageio.ImageReader;
+import javax.imageio.spi.ImageReaderSpi;
+import javax.imageio.stream.ImageInputStream;
+
+public class BMPImageReaderSpi extends ImageReaderSpi {
+
+ static final String vendorName = "GNU";
+ static final String version = "0.1";
+ static final String readerClassName =
+ "gnu.javax.imageio.bmp.BMPImageReader";
+ static final String[] names = { "Microsoft Windows BMP" };
+ static final String[] suffixes = { ".bmp", ".bm" };
+ static final String[] MIMETypes = {
+ "image/bmp",
+ "image/x-windows-bmp"};
+ static final String[] writerSpiNames =
+ { "gnu.javax.imageio.bmp.BMPImageWriterSpi" };
+
+ 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 BMPImageReaderSpi() {
+ super(vendorName, version,
+ names, suffixes, MIMETypes,
+ readerClassName,
+ STANDARD_INPUT_TYPE, // Accept ImageInputStreams
+ writerSpiNames,
+ supportsStandardStreamMetadataFormat,
+ nativeStreamMetadataFormatName,
+ nativeStreamMetadataFormatClassName,
+ extraStreamMetadataFormatNames,
+ extraStreamMetadataFormatClassNames,
+ supportsStandardImageMetadataFormat,
+ nativeImageMetadataFormatName,
+ nativeImageMetadataFormatClassName,
+ extraImageMetadataFormatNames,
+ extraImageMetadataFormatClassNames);
+ }
+
+ public String getDescription(Locale locale) {
+ return "Microsoft BMP v3";
+ }
+
+ public boolean canDecodeInput(Object input)
+ throws IOException {
+ if (!(input instanceof ImageInputStream))
+ return false;
+
+ ImageInputStream in = (ImageInputStream)input;
+ boolean retval;
+
+ in.mark();
+ try {
+ new BMPFileHeader(in);
+ retval = true;
+ } catch(BMPException e){
+ retval = false;
+ }
+ in.reset();
+
+ return retval;
+ }
+
+ public ImageReader createReaderInstance(Object extension) {
+ return new BMPImageReader(this);
+ }
+}
diff --git a/libjava/classpath/gnu/javax/imageio/bmp/BMPImageWriter.java b/libjava/classpath/gnu/javax/imageio/bmp/BMPImageWriter.java
new file mode 100644
index 000000000..407e66a72
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/BMPImageWriter.java
@@ -0,0 +1,195 @@
+/* BMPImageWriter.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.io.IOException;
+
+import javax.imageio.IIOImage;
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.ImageWriter;
+import javax.imageio.metadata.IIOMetadata;
+import javax.imageio.spi.ImageWriterSpi;
+import javax.imageio.stream.ImageOutputStream;
+
+public class BMPImageWriter
+ extends ImageWriter
+{
+ protected BMPEncoder encoder;
+ protected BMPFileHeader fileHeader;
+ protected BMPInfoHeader infoHeader;
+
+ /**
+ * Construct an bmp image writer.
+ *
+ * @param originatingProvider - the provider that is constructing this image
+ * writer, or null
+ */
+ protected BMPImageWriter(ImageWriterSpi originatingProvider)
+ {
+ super(originatingProvider);
+ encoder = null;
+ fileHeader = null;
+ infoHeader = null;
+ }
+
+ /**
+ * Convert IIOMetadata from an input reader format, returning an IIOMetadata
+ * suitable for use by an image writer. The ImageTypeSpecifier specifies the
+ * destination image type. An optional ImageWriteParam argument is available
+ * in case the image writing parameters affect the metadata conversion.
+ *
+ * @param inData - the metadata coming from an image reader
+ * @param imageType - the output image type of the writer
+ * @param param - the image writing parameters or null
+ * @return the converted metadata that should be used by the image writer, or
+ * null if this ImageTranscoder has no knowledge of the input metadata
+ * @exception IllegalArgumentException if either inData or imageType is null
+ */
+ public IIOMetadata convertImageMetadata(IIOMetadata inData,
+ ImageTypeSpecifier imageType,
+ ImageWriteParam param)
+ {
+ // FIXME: Support metadata.
+ if (inData == null || imageType == null)
+ throw new IllegalArgumentException("IIOMetadata and ImageTypeSpecifier cannot be null.");
+ return null;
+ }
+
+ /**
+ * Convert IIOMetadata from an input stream format, returning an
+ * IIOMetadata suitable for use by an image writer.
+ *
+ * An optional ImageWriteParam argument is available in case the
+ * image writing parameters affect the metadata conversion.
+ *
+ * @param inData - the metadata coming from an input image stream
+ * @param param - the image writing parameters or null
+ * @return the converted metadata that should be used by the image
+ * writer, or null if this ImageTranscoder has no knowledge of the
+ * input metadata
+ *
+ * @exception IllegalArgumentException if inData is null
+ */
+ public IIOMetadata convertStreamMetadata (IIOMetadata inData,
+ ImageWriteParam param)
+ {
+ // FIXME: Support metadata.
+ if (inData == null)
+ throw new IllegalArgumentException("IIOMetadata cannot be null.");
+ return null;
+ }
+
+ /**
+ * Get a metadata object appropriate for encoding an image specified
+ * by the given image type specifier and optional image write
+ * parameters.
+ *
+ * @param imageType - an image type specifier
+ * @param param - image writing parameters, or null
+ * @return a metadata object appropriate for encoding an image of
+ * the given type with the given parameters
+ */
+ public IIOMetadata getDefaultImageMetadata (ImageTypeSpecifier imageType, ImageWriteParam param)
+ {
+ // FIXME: Support metadata.
+ return null;
+ }
+
+ /**
+ * Get a metadata object appropriate for encoding the default image
+ * type handled by this writer, optionally considering image write
+ * parameters.
+ *
+ * @param param - image writing parameters, or null
+ * @return a metadata object appropriate for encoding an image of
+ * the default type with the given parameters
+ */
+ public IIOMetadata getDefaultStreamMetadata (ImageWriteParam param)
+ {
+ // FIXME: Support metadata.
+ return null;
+ }
+
+ /**
+ * Write an image stream, including thumbnails and metadata to the
+ * output stream. The output must have been set prior to this
+ * method being called. Metadata associated with the stream may be
+ * supplied, or it can be left null. IIOImage may contain raster
+ * data if this writer supports rasters, or it will contain a
+ * rendered image. Thumbnails are resized if need be. Image
+ * writing parameters may be specified to affect writing, or may be
+ * left null.
+ *
+ * @param streamMetadata - metadata associated with this stream, or
+ * null
+ * @param image - an IIOImage containing image data, metadata and
+ * thumbnails to be written
+ * @param param - image writing parameters, or null
+ * @exception IOException if a write error occurs
+ * @throws BMPException if the encoder has not been initialized.
+ */
+ public void write(IIOMetadata streamMetadata, IIOImage image,
+ ImageWriteParam param) throws IOException, BMPException
+ {
+ checkStream();
+ ImageOutputStream out = (ImageOutputStream) output;
+ fileHeader = new BMPFileHeader(out, image);
+ infoHeader = new BMPInfoHeader(out, image, param);
+ encoder = BMPEncoder.getEncoder(fileHeader, infoHeader);
+
+ if (encoder != null)
+ encoder.encode(out, streamMetadata, image, param);
+ else
+ throw new BMPException("Encoder has not been initialized.");
+ }
+
+ /**
+ * Checks the output stream.
+ *
+ * @throws IOException if there is an error with the output stream
+ */
+ private void checkStream() throws IOException
+ {
+ if (!(output instanceof ImageOutputStream))
+ throw new IllegalStateException("Output not an ImageOutputStream.");
+ if (output == null)
+ throw new IllegalStateException("No output stream.");
+ }
+}
diff --git a/libjava/classpath/gnu/javax/imageio/bmp/BMPImageWriterSpi.java b/libjava/classpath/gnu/javax/imageio/bmp/BMPImageWriterSpi.java
new file mode 100644
index 000000000..e158dcfd7
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/BMPImageWriterSpi.java
@@ -0,0 +1,148 @@
+/* BMPImageWriterSpi.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.util.Locale;
+
+import javax.imageio.ImageTypeSpecifier;
+import javax.imageio.ImageWriter;
+import javax.imageio.spi.ImageWriterSpi;
+
+public class BMPImageWriterSpi
+ extends ImageWriterSpi
+{
+
+ static final String vendorName = "GNU";
+ static final String version = "0.1";
+ static final String writerClassName = "gnu.javax.imageio.bmp.BMPImageWriter";
+ static final String[] names = { "bmp", "BMP", "Microsoft Windows BMP" };
+ static final String[] suffixes = { ".bmp", ".bm" };
+ static final String[] MIMETypes = { "image/bmp", "image/x-windows-bmp" };
+ static final String[] readerSpiNames = { "gnu.javax.imageio.bmp.BMPImageReaderSpi" };
+
+ 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 BMPImageWriter writerInstance;
+
+ public BMPImageWriterSpi()
+ {
+ super(vendorName, version, names, suffixes, MIMETypes, writerClassName,
+ STANDARD_OUTPUT_TYPE, readerSpiNames, supportsStandardStreamMetadataFormat,
+ nativeStreamMetadataFormatName, nativeStreamMetadataFormatClassName,
+ extraStreamMetadataFormatNames, extraStreamMetadataFormatClassNames,
+ supportsStandardImageMetadataFormat, nativeImageMetadataFormatName,
+ nativeImageMetadataFormatClassName, extraImageMetadataFormatNames,
+ extraImageMetadataFormatClassNames);
+ }
+
+ /**
+ * Returns true if the image can be encoded.
+ *
+ * @param type - the image type specifier.
+ * @return true if image can be encoded, otherwise false.
+ */
+ public boolean canEncodeImage(ImageTypeSpecifier type)
+ {
+ if (type == null)
+ return false;
+
+ BMPInfoHeader ih = writerInstance.infoHeader;
+ if (ih != null)
+ {
+ int compressionType = ih.getCompression();
+ int bytes = type.getColorModel().getPixelSize();
+ if ((compressionType == BMPInfoHeader.BI_RLE4 && (bytes != 4 || bytes != 8))
+ || (compressionType == BMPInfoHeader.BI_RGB && ((bytes != 1
+ || bytes != 4
+ || bytes != 8
+ || bytes != 16
+ || bytes != 24
+ || bytes != 32))))
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Creates an instance of ImageWriter using the given extension.
+ *
+ * @param extension - the provider that is constructing this image writer, or
+ * null
+ */
+ public ImageWriter createWriterInstance(Object extension)
+ {
+ if (extension != null && extension instanceof ImageWriterSpi)
+ writerInstance = new BMPImageWriter((ImageWriterSpi) extension);
+ else
+ writerInstance = new BMPImageWriter(this);
+ return writerInstance;
+ }
+
+ /**
+ * Gets the instance of ImageWriter, if already created.
+ */
+ public BMPImageWriter getWriterInstance()
+ {
+ if (writerInstance != null)
+ return writerInstance;
+ return (BMPImageWriter) createWriterInstance(null);
+ }
+
+ /**
+ * Returns a short description of this service provider that can be
+ * presented to a human user.
+ *
+ * @param locale - the locale for which the description string should
+ * be localized.
+ */
+ public String getDescription(Locale locale)
+ {
+ return "Microsoft BMP v3";
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/imageio/bmp/BMPInfoHeader.java b/libjava/classpath/gnu/javax/imageio/bmp/BMPInfoHeader.java
new file mode 100644
index 000000000..e14afdb04
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/BMPInfoHeader.java
@@ -0,0 +1,317 @@
+/* BMPInfoHeader.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you 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.Dimension;
+import java.awt.image.ColorModel;
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+import javax.imageio.IIOImage;
+import javax.imageio.ImageWriteParam;
+import javax.imageio.stream.ImageInputStream;
+import javax.imageio.stream.ImageOutputStream;
+
+public class BMPInfoHeader
+{
+ /** Size of the bitmap info header */
+ protected int biSize;
+
+ /** Pixel width of the bitmap */
+ protected int biWidth;
+
+ /** Pixel height of the bitmap */
+ protected int biHeight;
+
+ /** Number of bitplanes = 1 */
+ protected short biPlanes;
+
+ /** Number of bpp = 1,4,8,24 */
+ protected short biBitCount;
+
+ /** Compression type, RGB8, RLE8, RLE4, BITFIELDS */
+ protected int biCompression;
+
+ /** Byte size of the uncompressed bitmap, can be 0. */
+ protected int biSizeImage;
+
+ /** X resolution, dots per meter */
+ protected int biXPelsPerMeter;
+
+ /** Y resolution, dots per meter */
+ protected int biYPelsPerMeter;
+
+ /** Number of colors used (palette only, can be 0 for all) */
+ protected int biClrUsed;
+
+ /** Number of 'important' colors, 0 for all */
+ protected int biClrImportant;
+
+ /** BITMAPINFOHEADER is 40 bytes */
+ public static final int SIZE = 40;
+
+ /**
+ * Compression types
+ */
+ public static final int BI_RGB = 0;
+ public static final int BI_RLE8 = 1;
+ public static final int BI_RLE4 = 2;
+ public static final int BI_BITFIELDS = 3;
+
+ /**
+ * Creates the header from an input stream, which is not closed.
+ *
+ * @param in - the image input stream
+ * @throws IOException if an I/O error occured.
+ * @throws BMPException if the header was invalid
+ */
+ public BMPInfoHeader(ImageInputStream in) throws IOException, BMPException
+ {
+ byte[] data = new byte[SIZE];
+
+ if (in.read(data) != SIZE)
+ throw new IOException("Couldn't read header.");
+ ByteBuffer buf = ByteBuffer.wrap(data);
+ buf.order(ByteOrder.LITTLE_ENDIAN);
+
+ int n;
+ if ((n = buf.getInt()) != SIZE)
+ throw new BMPException("Invalid BITMAPINFOHEADER size: " + n);
+
+ biWidth = buf.getInt();
+ biHeight = buf.getInt();
+ biPlanes = buf.getShort();
+ setBitCount(buf.getShort());
+ setCompression(buf.getInt());
+ biSizeImage = buf.getInt();
+ biXPelsPerMeter = buf.getInt();
+ biYPelsPerMeter = buf.getInt();
+ biClrUsed = buf.getInt();
+ biClrImportant = buf.getInt();
+ }
+
+ /**
+ * Creates the info header from an output stream, which is not closed.
+ *
+ * @param out - the image output stream
+ * @param im - the image
+ * @param param - the image write param.
+ * @throws IOException if an I/O error occured.
+ */
+ public BMPInfoHeader(ImageOutputStream out, IIOImage im, ImageWriteParam param) throws IOException
+ {
+ RenderedImage img = im.getRenderedImage();
+ ColorModel cMod = img.getColorModel();
+
+ biSize = SIZE;
+ biWidth = img.getWidth();
+ biHeight = img.getHeight();
+ biPlanes = 1;
+
+ if (param != null && param.canWriteCompressed())
+ {
+ String compType = param.getCompressionType();
+ if (compType.equals("BI_RLE8"))
+ {
+ biCompression = BI_RLE8;
+ biBitCount = 8;
+ }
+ else if (compType.equals("BI_RLE4"))
+ {
+ biCompression = BI_RLE4;
+ biBitCount = 4;
+ }
+ else
+ {
+ biCompression = BI_RGB;
+ biBitCount = (short) cMod.getPixelSize();
+ }
+ }
+ else
+ {
+ biBitCount = (short) cMod.getPixelSize();
+ biCompression = BI_RGB;
+ }
+
+ biXPelsPerMeter = 0x0;
+ biYPelsPerMeter = 0x0;
+ biClrUsed = 0;
+ biClrImportant = 0;
+ biSizeImage = ((biWidth * biHeight) * 3)
+ + ((4 - ((biWidth * 3) % 4)) * biHeight);
+ out.write(intToDWord(biSize));
+ out.write(intToDWord(biWidth));
+ out.write(intToDWord(biHeight));
+ out.write(intToWord(biPlanes));
+ out.write(intToWord(biBitCount));
+ out.write(intToDWord(biCompression));
+ out.write(intToDWord(biSizeImage));
+ out.write(intToDWord(biXPelsPerMeter));
+ out.write(intToDWord(biYPelsPerMeter));
+ out.write(intToDWord(biClrUsed));
+ out.write(intToDWord(biClrImportant));
+ }
+
+ /**
+ * Converts an int to a word, where the return value is stored in a
+ * 2-byte array.
+ *
+ * @param val - the value to convert
+ * @return the array
+ */
+ private byte[] intToWord(int val)
+ {
+ byte b[] = new byte[2];
+ b[0] = (byte) (val & 0x00FF);
+ b[1] = (byte) ((val >> 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<w;x++)
+ data[x + y*w] = (short)((scanline[x*2] & (0xFF)) |
+ ((scanline[x*2+1] & (0xFF)) << 8));
+ }
+
+ ColorModel cm = new DirectColorModel(16,
+ bitmasks[0], bitmasks[1], bitmasks[2]);
+ SampleModel sm = new SinglePixelPackedSampleModel(DataBuffer.TYPE_USHORT,
+ w, h,
+ bitmasks);
+ DataBuffer db = new DataBufferUShort(data, w*h, 0);
+ WritableRaster raster = Raster.createWritableRaster(sm, db, null);
+ return new BufferedImage(cm, raster, false, null);
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/imageio/bmp/DecodeBF32.java b/libjava/classpath/gnu/javax/imageio/bmp/DecodeBF32.java
new file mode 100644
index 000000000..bfa469488
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/DecodeBF32.java
@@ -0,0 +1,103 @@
+/* DecodeBF32.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you 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.DataBufferInt;
+import java.awt.image.SinglePixelPackedSampleModel;
+import java.awt.image.SampleModel;
+import java.awt.Dimension;
+
+public class DecodeBF32 extends BMPDecoder {
+ private int[] bitmasks;
+ private boolean useDefaultMasks;
+
+ public DecodeBF32(BMPFileHeader fh, BMPInfoHeader ih,
+ boolean udm){
+ super(fh,ih);
+
+ useDefaultMasks = udm;
+ if(useDefaultMasks)
+ bitmasks = new int[] { 0x00FF0000, 0x0000FF00, 0x000000FF };
+ }
+
+ 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 << 2;
+ int[] data = new int[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<w;x++)
+ data[x + y*w] = ((scanline[x<<2] & (0xFF)) |
+ ((scanline[(x<<2)+1] & (0xFF)) << 8) |
+ ((scanline[(x<<2)+2] & (0xFF)) << 16) |
+ ((scanline[(x<<2)+3] & (0xFF)) << 24));
+ }
+
+ ColorModel cm = new DirectColorModel(32,
+ bitmasks[0], bitmasks[1], bitmasks[2]);
+ SampleModel sm = new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT,
+ w, h,
+ bitmasks);
+ DataBuffer db = new DataBufferInt(data, w*h);
+ WritableRaster raster = Raster.createWritableRaster(sm, db, null);
+
+ return new BufferedImage(cm, raster, false, null);
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB1.java b/libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB1.java
new file mode 100644
index 000000000..ca81bc433
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB1.java
@@ -0,0 +1,94 @@
+/* DecodeRGB1.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you 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.MultiPixelPackedSampleModel;
+import java.awt.image.SampleModel;
+import java.awt.Dimension;
+
+public class DecodeRGB1 extends BMPDecoder {
+
+ public DecodeRGB1(BMPFileHeader fh, BMPInfoHeader ih){
+ super(fh, ih);
+ }
+
+ 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();
+ int size = (w*h)>>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<scansize;x++)
+ data[x + y*scansize] = scanline[x];
+ }
+
+ SampleModel sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
+ w, h, 1);
+
+ DataBuffer db = new DataBufferByte(data, size, 0);
+ WritableRaster raster = Raster.createWritableRaster(sm, db, null);
+
+ return new BufferedImage(palette, raster, false, null);
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB24.java b/libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB24.java
new file mode 100644
index 000000000..0ddcc434e
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB24.java
@@ -0,0 +1,77 @@
+/* DecodeRGB24.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you 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.Dimension;
+
+public class DecodeRGB24 extends BMPDecoder {
+
+ public DecodeRGB24(BMPFileHeader fh, BMPInfoHeader ih){
+ super(fh, ih);
+ }
+
+ public BufferedImage decode(ImageInputStream in) throws IOException, BMPException {
+ skipToImage(in);
+
+ Dimension d = infoHeader.getSize();
+ int h = (int)d.getHeight();
+ int w = (int)d.getWidth();
+ BufferedImage image = new BufferedImage(w, h,
+ BufferedImage.TYPE_INT_RGB);
+ // BMP scanlines are padded to dword offsets
+ int scansize = ((w*3 & 3) != 0)? w*3 + 4 - (w*3 & 3): w*3;
+ int[] data = new int[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<w;x++)
+ data[x + y*w] = scanline[x*3] +
+ (scanline[x*3+1] << 8) +
+ (scanline[x*3+2] << 16);
+ }
+ image.setRGB(0, 0, w, h, data, 0, w);
+ return image;
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB4.java b/libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB4.java
new file mode 100644
index 000000000..a904ef745
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB4.java
@@ -0,0 +1,90 @@
+/* DecodeRGB4.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you 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.MultiPixelPackedSampleModel;
+import java.awt.image.SampleModel;
+import java.awt.Dimension;
+
+public class DecodeRGB4 extends BMPDecoder {
+
+ public DecodeRGB4(BMPFileHeader fh, BMPInfoHeader ih){
+ super(fh, ih);
+ }
+
+ 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();
+ int size = (w*h) >> 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<wbytes;x++)
+ data[x + y*wbytes] = scanline[x];
+ }
+ SampleModel sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
+ w, h, 4);
+
+ DataBuffer db = new DataBufferByte(data, w*h, 0);
+ WritableRaster raster = Raster.createWritableRaster(sm, db, null);
+
+ return new BufferedImage(palette, raster, false, null);
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB8.java b/libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB8.java
new file mode 100644
index 000000000..218047e5d
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/DecodeRGB8.java
@@ -0,0 +1,88 @@
+/* DecodeRGB8.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you 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 DecodeRGB8 extends BMPDecoder {
+
+ public DecodeRGB8(BMPFileHeader fh, BMPInfoHeader ih){
+ super(fh, ih);
+ }
+
+ 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();
+
+ // BMP scanlines are padded to dword offsets
+ int scansize = ((w & 3) != 0)? w + 4 - (w & 3): w;
+ byte[] data = new byte[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<w;x++)
+ data[x + y*w] = scanline[x];
+ }
+
+ 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);
+ }
+
+}
diff --git a/libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE4.java b/libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE4.java
new file mode 100644
index 000000000..1c116c247
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/DecodeRLE4.java
@@ -0,0 +1,175 @@
+/* DecodeRLE4.java --
+ Copyright (C) 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you 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.MultiPixelPackedSampleModel;
+import java.awt.image.SampleModel;
+import java.awt.Dimension;
+
+public class DecodeRLE4 extends BMPDecoder {
+
+ public DecodeRLE4(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 MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
+ w, h, 4);
+
+ 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>>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<length;i++){
+ if((i&1) == 0) // copy high to low
+ data[((x+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<length;i++)
+ data[(h-y-1)*w + i + (x >> 1)] = cmd[1];
+ } else {
+ for(int i=0;i<length;i++){
+ if((i&1) == 0) // copy high to low
+ data[((x+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<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/bmp/EncodeRGB1.java b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB1.java
new file mode 100644
index 000000000..ffe671dc0
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB1.java
@@ -0,0 +1,128 @@
+/* EncodeRGB1.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 EncodeRGB1
+ 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 EncodeRGB1(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/EncodeRGB16.java b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB16.java
new file mode 100644
index 000000000..a5450cc67
--- /dev/null
+++ b/libjava/classpath/gnu/javax/imageio/bmp/EncodeRGB16.java
@@ -0,0 +1,129 @@
+/* EncodeRGB16.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 EncodeRGB16
+ 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 EncodeRGB16(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[2];
+ 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);
+
+ 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<p>
+ *
+ * @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<Vt)
+ {
+ Vt=(-1 << t)+1;
+ diff=diff+Vt;
+ }
+ return diff;
+ }
+
+ /**
+ * Generated from FIGURE F.16 - Procedure for DECODE on
+ * ISO DIS 10918-1. Requirements and Guidelines<p>
+ *
+ * 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.
+ * <p>This is used exclusively in the JPEG DCT encoding.</p>
+ */
+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 <code>true</code> if this PNG is indexed-color
+ */
+ public boolean isIndexed()
+ {
+ return (colorType == INDEXED);
+ }
+
+ /**
+ * Returns <code>true</code> 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 <code>obj</code> 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<ObjectName,ServerInfo> beans =
+ new ConcurrentHashMap<ObjectName,ServerInfo>();
+
+ /**
+ * 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<NotificationListener,NotificationListener> listeners =
+ new ConcurrentHashMap<NotificationListener,NotificationListener>();
+ }
+
+ /**
+ * 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 <code>null</code> if <code>this</code>
+ * 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 <code>null</code> 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
+ * <code>null</code> 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)
+ * <code>MBeanPermission(className, null, name,
+ * "addNotificationListener")</code>}.
+ * @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);
+ }
+ }
+
+ /**
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @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
+ * <code>null</code> 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)
+ * <code>MBeanPermission(className, null, name,
+ * "addNotificationListener")</code>}.
+ * @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);
+ }
+
+ /**
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * If the name supplied is <code>null</code>, 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.
+ * </p>
+ * <p>
+ * This method is equivalent to calling {@link
+ * #createMBean(String, ObjectName, Object[], String[])
+ * <code>createMBean(className, name, (Object[]) null,
+ * (String[]) null)</code>} with <code>null</code> parameters
+ * and signature.
+ * </p>
+ *
+ * @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
+ * <code>null</code> 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 <code>instantiate</code>
+ * and <code>registerMBean</code> 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);
+ }
+
+ /**
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * If the name supplied is <code>null</code>, 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.
+ * </p>
+ *
+ * @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
+ * <code>null</code> 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 <code>instantiate</code>
+ * and <code>registerMBean</code> 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);
+ }
+
+ /**
+ * <p>
+ * 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 <code>null</code>,
+ * then the same class loader as was used to load the server
+ * is used.
+ * </p>
+ * <p>
+ * If the name supplied is <code>null</code>, 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.
+ * </p>
+ * <p>
+ * This method is equivalent to calling {@link
+ * #createMBean(String, ObjectName, ObjectName, Object[], String)
+ * <code>createMBean(className, name, loaderName, (Object[]) null,
+ * (String) null)</code>} with <code>null</code> parameters
+ * and signature.
+ * </p>
+ *
+ * @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
+ * <code>null</code> 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 <code>instantiate</code>
+ * and <code>registerMBean</code> 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);
+ }
+
+ /**
+ * <p>
+ * 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 <code>null</code>,
+ * then the same class loader as was used to load the server
+ * is used.
+ * </p>
+ * <p>
+ * If the name supplied is <code>null</code>, 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.
+ * </p>
+ *
+ * @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
+ * <code>null</code> 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 <code>instantiate</code>
+ * and <code>registerMBean</code> 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)
+ * <code>MBeanPermission(className, null, name,
+ * "getClassLoaderFor")</code>
+ */
+ 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)
+ * <code>MBeanPermission(null, null, null,
+ * "getClassLoaderRepository")</code>
+ */
+ 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 <code>null</code> 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 <code>null</code>
+ * 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)
+ * <code>MBeanPermission(className, null, loader,
+ * "getClassLoader")</code>
+ */
+ 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
+ * <code>null</code> 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)
+ * <code>MBeanPermission(className, name, bean,
+ * "getAttribute")</code>}.
+ * @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
+ * <code>null</code> 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)
+ * <code>MBeanPermission(className, null, bean,
+ * "getAttribute")</code>}. Additionally,
+ * for an attribute name, <code>n</code>, the
+ * caller's permission must imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, n, bean,
+ * "getAttribute")</code>} 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
+ * <code>null</code>, then the class loader of the server will be
+ * returned. If <code>l</code> is the requested class loader,
+ * and <code>r</code> is the actual class loader returned, then
+ * either <code>l</code> and <code>r</code> 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)
+ * <code>MBeanPermission(className, null, name,
+ * "getClassLoader")</code>
+ */
+ 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
+ * <code>l</code> is the requested class loader, and <code>r</code>
+ * is the actual class loader returned, then either <code>l</code>
+ * and <code>r</code> 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)
+ * <code>MBeanPermission(className, null, name,
+ * "getClassLoaderFor")</code>
+ */
+ 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)
+ * <code>MBeanPermission(null, null, null,
+ * "getClassLoaderRepository")</code>
+ */
+ 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)
+ * <code>MBeanPermission(null, null, name,
+ * "getDomains")</code>}. Additionally,
+ * for an domain, <code>d</code>, the
+ * caller's permission must imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(null, null,
+ * new ObjectName("d:x=x"), "getDomains")</code>}
+ * 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<String> domains = new HashSet<String>();
+ Iterator<ObjectName> 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)
+ * <code>MBeanPermission(className, null, name,
+ * "getMBeanInfo")</code>}.
+ * @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)
+ * <code>MBeanPermission(className, null, name,
+ * "getObjectInstance")</code>
+ * @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();
+ }
+
+ /**
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * This method is equivalent to calling {@link
+ * #instantiate(String, Object[], String[])
+ * <code>instantiate(name, (Object[]) null, (String[]) null)</code>}
+ * with <code>null</code> parameters and signature.
+ * </p>
+ *
+ * @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
+ * <code>null</code> name.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, null,
+ * "instantiate")</code>}.
+ * @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
+ * <code>null</code> name.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, null,
+ * "instantiate")</code>}.
+ */
+ 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");
+ }
+ }
+
+ /**
+ * <p>
+ * Creates an instance of the specified class using the supplied
+ * class loader. If the class loader given is <code>null</code>,
+ * 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.
+ * </p>
+ * <p>
+ * This method is equivalent to calling {@link
+ * #instantiate(String, ObjectName, Object[], String[])
+ * <code>instantiate(name, loaderName, (Object[]) null,
+ * (String[]) null)</code>} with <code>null</code> parameters
+ * and signature.
+ * </p>
+ *
+ * @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
+ * <code>null</code> name.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, null,
+ * "instantiate")</code>}.
+ * @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 <code>null</code>,
+ * 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
+ * <code>null</code> name.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, null,
+ * "instantiate")</code>}.
+ */
+ 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
+ * <code>null</code> 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)
+ * <code>MBeanPermission(className, name, bean,
+ * "invoke")</code>}.
+ * @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));
+ }
+ }
+
+ /**
+ * <p>
+ * Returns true if the specified management bean is an instance
+ * of the supplied class.
+ * </p>
+ * <p>
+ * A bean, B, is an instance of a class, C, if either of the following
+ * conditions holds:
+ * </p>
+ * <ul>
+ * <li>The class name in B's {@link MBeanInfo} is equal to the supplied
+ * name.</li>
+ * <li>Both the class of B and C were loaded by the same class loader,
+ * and B is assignable to C.</li>
+ * </ul>
+ *
+ * @param name the name of the management bean.
+ * @param className the name of the class to test if <code>name</code> 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)
+ * <code>MBeanPermission(className, null, name,
+ * "isInstanceOf")</code>
+ */
+ 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
+ * <code>null</code> 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);
+ }
+
+ /**
+ * <p>
+ * 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:
+ * </p>
+ * <ol>
+ * <li>Pattern matching is performed using the supplied
+ * {@link ObjectName}.</li>
+ * <li>The supplied query expression is applied.</li>
+ * </ol>
+ * <p>
+ * If both the object name and the query expression are <code>null</code>,
+ * or the object name has no domain and no key properties,
+ * no filtering will be performed and all beans are returned.
+ * </p>
+ *
+ * @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)
+ * <code>MBeanPermission(null, null, name,
+ * "queryMBeans")</code>}. Additionally,
+ * for an bean, <code>b</code>, the
+ * caller's permission must imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, b, name,
+ * "queryMBeans")</code>} 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<ObjectInstance> queryMBeans(ObjectName name, QueryExp query)
+ {
+ checkSecurity(name, null, "queryMBeans");
+ Set<ObjectInstance> results = new HashSet<ObjectInstance>();
+ for (Map.Entry<ObjectName,ServerInfo> 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;
+ }
+
+ /**
+ * <p>
+ * 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:
+ * </p>
+ * <ol>
+ * <li>Pattern matching is performed using the supplied
+ * {@link ObjectName}.</li>
+ * <li>The supplied query expression is applied.</li>
+ * </ol>
+ * <p>
+ * If both the object name and the query expression are <code>null</code>,
+ * or the object name has no domain and no key properties,
+ * no filtering will be performed and all beans are returned.
+ * </p>
+ *
+ * @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)
+ * <code>MBeanPermission(null, null, name,
+ * "queryNames")</code>}. Additionally,
+ * for an name, <code>n</code>, the
+ * caller's permission must imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, n, name,
+ * "queryNames")</code>} 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
+ * <code>queryMBeans</code> permissions are available.
+ */
+ public Set<ObjectName> queryNames(ObjectName name, QueryExp query)
+ {
+ checkSecurity(name, null, "queryNames");
+ Set<ObjectName> results = new HashSet<ObjectName>();
+ 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 <code>null</code>, 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 <code>null</code> 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
+ * <code>null</code> object.
+ * @throws SecurityException if a security manager exists and the
+ * caller's permissions don't imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, null, name,
+ * "registerMBean")</code>}. <code>className</code>
+ * 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)
+ * <code>MBeanTrustPermission("register")</code>}.
+ * 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)
+ * <code>MBeanPermission(className, null, name,
+ * "removeNotificationListener")</code>}.
+ * @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.
+ * <code>null</code> 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)
+ * <code>MBeanPermission(className, null, name,
+ * "removeNotificationListener")</code>}.
+ * @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)
+ * <code>MBeanPermission(className, null, name,
+ * "removeNotificationListener")</code>}.
+ * @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.
+ * <code>null</code> 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)
+ * <code>MBeanPermission(className, null, name,
+ * "removeNotificationListener")</code>}.
+ * @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
+ * <code>null</code> 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)
+ * <code>MBeanPermission(className, name, bean,
+ * "setAttribute")</code>}.
+ * @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
+ * <code>null</code> 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)
+ * <code>MBeanPermission(className, null, bean,
+ * "setAttribute")</code>}. Additionally,
+ * for an attribute name, <code>n</code>, the
+ * caller's permission must imply {@link
+ * MBeanPermission(String,String,ObjectName,String)
+ * <code>MBeanPermission(className, n, bean,
+ * "setAttribute")</code>} 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<Object> 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
+ * <code>null</code> 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)
+ * <code>MBeanPermission(className, null, name,
+ * "unregisterMBean")</code>}.
+ */
+ 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 <code>bean</code> 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 <code>bean</code> 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<Object> l = new ArrayList<Object>(elems.length);
+ for (Object elem : elems)
+ l.add(elem);
+ return l;
+ }
+ if (Map.class.isAssignableFrom(returnType))
+ {
+ TabularData data = (TabularData) otype;
+ Map<Object,Object> m = new HashMap<Object,Object>(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<OpenType<?>>(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<OpenType<?>>(depth, ot)
+ );
+ }
+ Method[] methods = c.getDeclaredMethods();
+ List<String> names = new ArrayList<String>();
+ List<OpenType<?>> types = new ArrayList<OpenType<?>>();
+ 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();
+ }
+
+ /**
+ * <p>
+ * 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:
+ * </p>
+ * <ul>
+ * <li>If T is non-generic and not an array, then the value
+ * of {@link java.lang.Class#getName()} is returned.</li>
+ * <li>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.</li>
+ * <li>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 '>'}.</li>
+ * </ul>
+ *
+ * @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: <br>
+ * 1. corbaloc:[iiop][version.subversion@]:host[:port]/key <br>
+ * 2. corbaloc:rir:[/key] <br>
+ * 3. corbaname:[iiop][version.subversion@]:host[:port]/key <br>
+ * 4. corbaname:rir:[/key] <br>
+ * 5. file://[file name]<br>
+ * 6. http://[url]<br>
+ * 7. ftp://[url]<br>
+ *
+ * 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 <code>list</code>.
+ */
+ 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 <code>String</code> component to this <code>Name</code>
+ * at the given index. The method modifies the current <code>Name</code> and
+ * then returns it.
+ *
+ * @exception ArrayIndexOutOfBoundsException if the given index is smaller
+ * then zero or greater then or equal to <code>size()</code>.
+ * @exception InvalidNameException if the given <code>String</code> is not a
+ * valid component for this <code>Name</code>.
+ */
+ 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 <code>String</code> component to the end of this
+ * <code>Name</code>. The method modifies the current <code>Name</code>
+ * and then returns it.
+ *
+ * @exception InvalidNameException if the given <code>String</code> is not a
+ * valid component for this <code>Name</code>.
+ */
+ 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 <code>Name</code> to this
+ * <code>Name</code> at the given index. Components after this index (if
+ * any) are shifted up. The method modifies the current <code>Name</code>
+ * and then returns it.
+ *
+ * @exception ArrayIndexOutOfBoundsException if the given index is smaller
+ * then zero or greater then or equal to <code>size()</code>.
+ * @exception InvalidNameException if any of the given components is not a
+ * valid component for this <code>Name</code>.
+ */
+ 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 <code>Name</code> to the end of this
+ * <code>Name</code>. The method modifies the current <code>Name</code>
+ * and then returns it.
+ *
+ * @exception InvalidNameException if any of the given components is not a
+ * valid component for this <code>Name</code>.
+ */
+ 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 <code>Name</code>. Returns a negative
+ * value if the given <code>Object</code> is smaller then this
+ * <code>Name</code>, a positive value if the <code>Object</code> is
+ * bigger, and zero if the are equal. If the <code>Object</code> is not of a
+ * class that can be compared to the class of this <code>Name</code> then a
+ * <code>ClassCastException</code> is thrown. Note that it is not guaranteed
+ * that <code>Name</code>s 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 <code>true</code> if this <code>Name</code> ends with the
+ * components of the given <code>Name</code>, <code>false</code>
+ * 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 <code>size()</code>.
+ */
+ public String get(int posn)
+ {
+ return content[from + posn];
+ }
+
+ /**
+ * Returns a non-null (but possibly empty) <code>Enumeration</code> of the
+ * components of the <code>Name</code> as <code>String</code>s.
+ */
+ public Enumeration getAll()
+ {
+ return new GnuNameEnum(0);
+ }
+
+ /**
+ * Returns the components till the given index as a <code>Name</code>. The
+ * returned <code>Name</code> 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 <code>size()</code>.
+ */
+ public Name getPrefix(int posn)
+ {
+ return new GnuName(content, from, posn);
+ }
+
+ /**
+ * Returns the components from the given index till the end as a
+ * <code>Name</code>. The returned <code>Name</code> 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 <code>size()</code>.
+ */
+ public Name getSuffix(int posn)
+ {
+ return new GnuName(content, from + posn, length - posn);
+ }
+
+ /**
+ * Returns <code>true</code> if the number of components of this
+ * <code>Name</code> is zero, <code>false</code> otherwise.
+ */
+ public boolean isEmpty()
+ {
+ return length == 0;
+ }
+
+ /**
+ * Removes the component at the given index from this <code>Name</code>.
+ * The method modifies the current <code>Name</code> 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 <code>Name</code>. The returned
+ * number can be zero.
+ */
+ public int size()
+ {
+ return length;
+ }
+
+ /**
+ * Returns <code>true</code> if this <code>Name</code> starts with the
+ * components of the given <code>Name</code>, <code>false</code>
+ * 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 <code>Name</code>. It will be a deep copy of all
+ * the components of the <code>Name</code> so that changes to components of
+ * the components does not change the component in this <code>Name</code>.
+ */
+ 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.
+ *
+ * <p>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.
+ *
+ * <p>As a simple example, that writes sessions to some object output
+ * stream:
+ *
+ * <pre>
+ char[] password = ...;
+ ObjectOutputStream out = ...;
+ ...
+ for (Session s : this)
+ {
+ s.prepare(password);
+ out.writeObject(s);
+ }</pre>
+ *
+ * <p>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:
+ *
+ * <pre>
+ char[] password = ...;
+ ObjectInputStream in = ...;
+ ...
+ while (hasMoreSessions(in))
+ {
+ Session s = (Session) in.readObject();
+ s.repair(password);
+ addToThisStore(s);
+ }</pre>
+ *
+ * @author Casey Marshall (csm@gnu.org)
+ */
+public abstract class AbstractSessionContext implements SSLSessionContext
+{
+ protected long timeout;
+ private static Class<? extends AbstractSessionContext>
+ 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.
+ *
+ * <p><strong>Note:</strong> this method requires that the caller have
+ * {@link SSLPermission} with target
+ * <code>gnu.javax.net.ssl.AbstractSessionContext</code> and action
+ * <code>setImplClass</code>.
+ *
+ * @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<? extends AbstractSessionContext> 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.
+ *
+ * <p>Subclasses implementing this class <strong>must not</strong>
+ * 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 <code>null</code> 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.
+ *
+ * <p>Subclasses implementing this class <strong>must not</strong>
+ * 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.
+ *
+ * <p>Subclasses implementing this class <strong>must not</strong>
+ * 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.
+ *
+ * <p>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<String, SecretKey> keys;
+
+ public PreSharedKeyManagerParameters()
+ {
+ keys = new LinkedHashMap<String, SecretKey>();
+ }
+
+ 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<String> 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<PrivateKey> privateKeys;
+ private List<X509Certificate[]> certChains;
+
+ // Constructor.
+ // -------------------------------------------------------------------------
+
+ public PrivateCredentials()
+ {
+ privateKeys = new LinkedList<PrivateKey>();
+ certChains = new LinkedList<X509Certificate[]>();
+ }
+
+ // Instance methods.
+ // -------------------------------------------------------------------------
+
+ public void add(InputStream certChain, InputStream privateKey)
+ throws CertificateException, InvalidKeyException, InvalidKeySpecException,
+ IOException, NoSuchAlgorithmException, WrongPaddingException
+ {
+ CertificateFactory cf = CertificateFactory.getInstance("X.509");
+ Collection<? extends Certificate> 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<PrivateKey> getPrivateKeys()
+ {
+ if (isDestroyed())
+ {
+ throw new IllegalStateException("this object is destroyed");
+ }
+ return privateKeys;
+ }
+
+ public List<X509Certificate[]> 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 <i>file</i> is <code>null</code>.
+ */
+ 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 <i>user</i>
+ */
+ 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 <code>null</code> if there is no
+ * entry for <i>user</i>.
+ */
+ KeyPair getKeyPair(String user);
+
+ /**
+ * Returns the salt value for the given user.
+ *
+ * @param user The user name.
+ * @return The salt for <i>user</i>'s entry, or <code>null</code>.
+ */
+ byte[] getSalt(String user);
+
+ /**
+ * Returns the password verifier for the given user.
+ *
+ * @param user The user name.
+ * @return <i>user</i>'s password verifier, or <code>null</code>.
+ */
+ 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 <em>fragment</em> of the record layer message
+ * &mdash; 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.
+ *
+ * <p>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<String,Object> values;
+ protected boolean valid;
+ protected boolean truncatedMac = false;
+ transient protected SecureRandom random;
+ transient protected SSLSessionContext context;
+
+ protected Session()
+ {
+ creationTime = System.currentTimeMillis();
+ values = new HashMap<String, Object>();
+ 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<String> 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.
+ *
+ * <p>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<DelegatedTask> 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<DelegatedTask>();
+ }
+
+ /**
+ * 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
+ * <code>fragment</code>, 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.
+ *
+ * <p>In the presence of a well-behaving peer, this should be called once
+ * the <code>ChangeCipherSpec</code> 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
+ * <code>ChangeCipherSpec</code> 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 <em>should</em> 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.
+ *
+ * <p>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.
+ *
+ * <p>SSLv3 uses the algorithm:
+ *
+ * <pre>
+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));</pre>
+ *
+ * @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<String,byte[]> attr = new HashMap<String,byte[]>(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<String,byte[]> attr = new HashMap<String,byte[]>(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<String,byte[]> attr = new HashMap<String,byte[]>(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<String, Object> params = new HashMap<String, Object>(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<String,byte[]> attr = new HashMap<String,byte[]>(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<ClassLoader>()
+ {
+ 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.
+ *
+ * <pre>
+ * struct {
+ * AlertLevel level;
+ * AlertDescription description;
+ * }
+ * </pre>
+ */
+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.
+ *
+ * <pre>
+ * enum { warning(1), fatal(2), (255) } AlertLevel;
+ * </pre>
+ */
+ 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.
+ *
+ * <p>Once the object is built, through various <em>setters</em> 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.
+ *
+ * <pre>opaque ASN.1Cert&lt;1..2^24-1&gt;;
+
+struct {
+ ASN.1Cert certificate_list&lt;0..2^24-1&gt;;
+} Certificate;</pre>
+ *
+ * @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<java.security.cert.Certificate> certificates ()
+ throws CertificateException, NoSuchAlgorithmException
+ {
+ LinkedList<java.security.cert.Certificate> list
+ = new LinkedList<java.security.cert.Certificate>();
+ 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<? extends java.security.cert.Certificate> 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.
+ *
+ * <pre>
+struct
+{
+ ClientCertificateType certificate_types&lt;1..2^8-1&gt;;
+ DistinguishedName certificate_authorities&lt;3..2^16-1&gt;;
+} CertificateRequest;
+</pre>
+ */
+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<ClientCertificateType> 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<X500Principal> 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;
+
+/**
+ * <pre>
+struct {
+ CertificateStatusType status_type;
+ select (status_type) {
+ case ocsp: OCSPStatusRequest;
+ } request;
+} CertificateStatusRequest;
+
+enum { ocsp(1), (255) } CertificateStatusType;
+
+struct {
+ ResponderID responder_id_list&lt;0..2^16-1&gt;;
+ Extensions request_extensions;
+} OCSPStatusRequest;
+
+opaque ResponderID&lt;1..2^16-1&gt;;
+opaque Extensions&lt;0..2^16-1&gt;;</pre>
+ *
+ * @author csm
+ */
+public class CertificateStatusRequest extends Value implements Iterable<byte[]>
+{
+ private ByteBuffer buffer;
+
+ public CertificateStatusRequest(final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public CertificateStatusRequest(CertificateStatusType type,
+ List<byte[]> 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<byte[]> 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<byte[]>
+ {
+ 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.
+ *
+ * <pre>
+enum {
+ individual_certs(0), pkipath(1), (255)
+} CertChainType;
+
+enum {
+ false(0), true(1)
+} Boolean;
+
+struct {
+ CertChainType type;
+ URLAndOptionalHash url_and_hash_list&lt;1..2^16-1&gt;;
+} CertificateURL;
+
+struct {
+ opaque url&lt;1..2^16-1&gt;;
+ Boolean hash_present;
+ select (hash_present) {
+ case false: struct {};
+ case true: SHA1Hash;
+ } hash;
+} URLAndOptionalHash;
+
+opaque SHA1Hash[20];</pre>
+ *
+ * @author csm
+ *
+ */
+public class CertificateURL extends Value implements Iterable<CertificateURL.URLAndOptionalHash>
+{
+ private ByteBuffer buffer;
+
+ public CertificateURL(final ByteBuffer buffer)
+ {
+ this.buffer = buffer;
+ }
+
+ public CertificateURL(CertChainType type, List<URLAndOptionalHash> 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<URLAndOptionalHash> iterator()
+ {
+ return new Iterator();
+ }
+
+ public class Iterator implements java.util.Iterator<URLAndOptionalHash>
+ {
+ 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<String> tlsSuiteNames = new LinkedList<String>();
+ private static final HashMap<String, CipherSuite> namesToSuites = new HashMap<String, CipherSuite>();
+
+ // 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<String> 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<CipherSuite>
+{
+ 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, <code>index &lt;=
+ * size ()</code>).
+ *
+ * @param index The index to put the suite.
+ * @param suite The CipherSuite object.
+ * @throws IndexOutOfBoundsException If <code>index</code> is not
+ * less than @{link #size()}, or if it is negative.
+ * @throws NullPointerException If <code>suite</code> is
+ * <code>null</code>.
+ * @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
+ * <code>remove</code> 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<CipherSuite> iterator ()
+ {
+ return new Iterator ();
+ }
+
+ /**
+ * An iterator for the elements in this list. The iterator supports
+ * only the <code>set</code> 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<CipherSuite>
+ {
+ 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<ClientCertificateType>
+{
+ 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<ClientCertificateType> 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<CertificateRequest.ClientCertificateType>
+ {
+ 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;
+
+/**
+ * <pre>
+ struct {
+ select (KeyExchangeAlgorithm) {
+ /* other cases for rsa, diffie_hellman, etc. &#42;/
+ case diffie_hellman_psk: /* NEW &#42;/
+ opaque psk_identity<0..2^16-1>;
+ ClientDiffieHellmanPublic public;
+ } exchange_keys;
+ } ClientKeyExchange;</pre>
+ *
+ * @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.
+ *
+ * <pre>
+struct {
+ select (PublicValueEncoding) {
+ case implicit: struct { };
+ case explicit: opaque dh_Yc&lt;1..2^16-1&gt;;
+ } dh_public;
+} ClientDiffieHellmanPublic;</pre>
+ */
+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<String> typeList = new LinkedList<String>();
+ for (ClientCertificateType t : types)
+ typeList.add(t.name());
+
+ X500PrincipalList issuers = req.authorities();
+ LinkedList<X500Principal> issuerList = new LinkedList<X500Principal>();
+ 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<Extension> extensions = new LinkedList<Extension>();
+ 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<CipherSuite> getSuites() throws SSLException
+ {
+ List<CipherSuite> suites = new LinkedList<CipherSuite>();
+ 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<CompressionMethod> getCompressionMethods()
+ {
+ List<CompressionMethod> methods = new LinkedList<CompressionMethod>();
+ 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<String> keyTypes;
+ private final List<X500Principal> issuers;
+
+ CertLoader(List<String> keyTypes, List<X500Principal> 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.
+ *
+ * <pre>
+struct
+{
+ ProtocolVersion client_version; // 2
+ Random random; // 32
+ SessionID session_id; // 1 + 0..32
+ CipherSuite cipher_suites&lt;2..2^16-1&gt;
+ CompressionMethod compression_methods&lt;1..2^8-1&gt;
+ Extension client_hello_extension_list&lt;0..2^16-1&gt;
+} ClientHello;
+</pre>
+ */
+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<CipherSuite> 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<CompressionMethod> 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.
+ *
+ * <p>The format of a version 2 client hello is:
+ *
+ * <pre>
+ 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&lt;&lt;8)|LSB]
+ char SESSION-ID-DATA[(MSB&lt;&lt;8)|LSB]
+ char CHALLENGE-DATA[(MSB&lt;&lt;8)|LSB]</pre>
+ */
+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<CipherSuite> cipherSpecs ()
+ {
+ int n = cipherSpecsLength ();
+ List<CipherSuite> l = new ArrayList<CipherSuite>(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.
+ *
+ * <pre>
+struct {
+ select (KeyExchangeAlgorithm) {
+ case rsa: EncryptedPreMasterSecret;
+ case diffie_hellman: ClientDiffieHellmanPublic;
+ } exchange_keys;
+} ClientKeyExchange;</pre>
+ */
+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;
+
+/**
+ * <pre>
+ struct {
+ select (KeyExchangeAlgorithm) {
+ /* other cases for rsa, diffie_hellman, etc. &#42;/
+ case psk: /* NEW &#42;/
+ opaque psk_identity&lt;0..2^16-1&gt;;
+ } exchange_keys;
+ } ClientKeyExchange;</pre>
+ *
+ * @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<CompressionMethod>
+{
+ 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, <code>index
+ * &lt;= size ()</code>).
+ *
+ * @param index The index to put the suite.
+ * @param method The CompressionMethod object.
+ * @throws IndexOutOfBoundsException If <code>index</code> is not
+ * less than @{link #size()}, or if it is negative.
+ * @throws NullPointerException If <code>suite</code> is
+ * <code>null</code>.
+ * @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
+ * <code>remove</code> 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<CompressionMethod> iterator ()
+ {
+ return new Iterator ();
+ }
+
+ /**
+ * An iterator for the elements in this list. The iterator supports
+ * only the <code>set</code> 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<CompressionMethod>
+ {
+ 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.
+ *
+ * <p><b>Contract for ByteBuffer-based constructed types:</b>
+ *
+ * <p>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 <em>will not</em> modify the position or
+ * limit of the buffer when doing read operations. That is, the position
+ * of the underlying buffer <em>should</em> 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).
+ *
+ * <p>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.
+ *
+ * <p>Thus, very often the code will use <em>absolute</em> 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 <code>null</code>.
+ * @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.
+ *
+ * <pre>
+enum { change_cipher_spec(20), alert(21), handshake(22),
+ application_data(23), (255) } ContentType;</pre>
+ *
+ * <p>There is also a "pseudo" content type, <code>client_hello_v2
+ * (1)</code>, 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;
+
+/**
+ * <p>Simple implementation of two-party Diffie-Hellman key agreement.</p>
+ *
+ * <p>The primes used in this class are from the following documents:</p>
+ *
+ * <ul>
+ * <li>D. Harkins and D. Carrel, "The Internet Key Exchange (IKE)", <a
+ * href="http://www.ietf.org/rfc/rfc2409.txt">RFC 2409</a>.</li>
+ * <li>T. Kivinen and M. Kojo, "More Modular
+ * Exponential (MODP) Diffie-Hellman groups for Internet Key Exchange
+ * (IKE)", <a href="http://www.ietf.org/rfc/rfc3526.txt">RFC
+ * 3526</a>.</li>
+ * </li>
+ *
+ * <p>The generator for all these primes is 2.</p>
+ */
+final class DiffieHellman
+{
+
+ // Class method.
+ // -------------------------------------------------------------------------
+
+ /**
+ * Get the system's Diffie-Hellman parameters, in which <i>g</i> is 2
+ * and <i>p</i> is determined by the property
+ * <code>"jessie.keypool.dh.group"</code>. The default value for <i>p</i>
+ * 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 }.
+ *
+ * <p>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.
+ *
+ * <pre>
+struct {
+ public-key-encrypted PreMasterSecret pre_master_secret;
+} EncryptedPreMasterSecret;</pre>
+ */
+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.
+ *
+ * <pre>
+ * struct {
+ * ExtensionType extension_type;
+ * opaque extension_data<0..2^16-1>;
+ * } Extension;</pre>
+ *
+ * @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:
+ *
+ * <tt> Extension extensions_list&lt;1..2^16-1&gt;</tt>
+ *
+ * @author csm
+ */
+public class ExtensionList implements Builder, Iterable<Extension>
+{
+ private final ByteBuffer buffer;
+ private int modCount;
+
+ public ExtensionList (ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ modCount = 0;
+ }
+
+ public ExtensionList(List<Extension> 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>i</i> to <i>e</i>. Note that setting an
+ * element at an index <b>may</b> invalidate any other elements that come
+ * after element at index <i>i</i>. In other words, no attempt is made to
+ * move existing elements in this list, and since extensions are variable
+ * length, you can <em>not</em> guarantee that extensions later in the list
+ * will still be valid.
+ *
+ * <p>Thus, elements of this list <b>must</b> 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>i</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<Extension> 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<Extension>
+ {
+ 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:
+ *
+ * <pre>
+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;
+};</pre>
+ */
+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 <code>length</code> 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.
+ *
+ * <pre>struct { } HelloRequest;</pre>
+ */
+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:
+ *
+ * <pre>
+ * {@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
+ * </pre>
+ *
+ */
+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<Object>()
+ {
+ 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<String> 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<ProtocolVersion>, 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.
+ *
+ * <pre>
+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:
+ *
+ * <pre>
+struct
+{
+ {@link ContentType} type;
+ {@link ProtocolVersion} version;
+ uint16 length;
+ opaque fragment[TLSPlaintext.length];
+} TLSPlaintext;
+</pre>
+ */
+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 <code>sink</code>.
+ *
+ * @param sink The sink for the fragment bytes.
+ * @return The number of bytes put into <code>sink</code>
+ */
+ 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 <i>type</i> is <code>null</code>.
+ */
+ 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 <i>version</i> is <code>null</code>.
+ */
+ 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 <code>gnu.javax.net.ssl.secureRandom</code> 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<CipherSuite> 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<CompressionMethod> comps = new ArrayList<CompressionMethod>(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:
+ *
+ * <pre>
+ * hash(MAC_write_secret, pad_2 +
+ * hash(MAC_write_secret + pad_1 + data));</pre>
+ *
+ * <p><tt>hash</tt> is e.g. MD5 or SHA-1, <tt>pad_1</tt> is the value
+ * 0x36 48 times for MD5 and 40 times for SHA-1, and <tt>pad_2</tt> 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<HandshakeCompletedListener> 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<HandshakeCompletedListener>();
+ 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<String,byte[]> 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<String,byte[]> 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;
+
+/**
+ * <pre>
+ struct {
+ select (KeyExchangeAlgorithm) {
+ /* other cases for rsa, diffie_hellman, etc. &#42;/
+ case diffie_hellman_psk: /* NEW &#42;/
+ opaque psk_identity_hint&lt;0..2^16-1&gt;;
+ ServerDHParams params;
+ };
+ } ServerKeyExchange;</pre>
+ *
+ * @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.
+ *
+ * <pre>
+struct
+{
+ opaque dh_p&lt;1..2^16-1&gt;;
+ opaque dh_g&lt;1..2^16-1&gt;;
+ opaque dh_Ys&lt;1..2^16-1&gt;;
+} ServerDHParams;
+</pre>
+ */
+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<KeyExchangeAlgorithm> kexes = new HashSet<KeyExchangeAlgorithm>(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<CipherSuite> suites = new HashSet<CipherSuite>();
+ 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<String> names
+ = new ArrayList<String>(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<ClientCertificateType> types
+ = new ArrayList<ClientCertificateType>(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<X500Principal> issuers
+ = new ArrayList<X500Principal>(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.
+ *
+ * <pre>
+struct
+{
+ ProtocolVersion server_version;
+ Random random;
+ SessionID session_id;
+ CipherSuite cipher_suite;
+ CompressionMethod compression_method;
+ Extensions server_hello_extension_list&lt;0..2^16-1&gt;
+} ServerHello;
+</pre>
+ *
+ * <p>Server hello messages may contain extra data after the
+ * <tt>compression_method</tt> 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.
+ *
+ * <pre>struct { } ServerHelloDone;</pre>
+ */
+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.
+ *
+ * <pre>
+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;
+</pre>
+ */
+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.
+ *
+ * <pre>
+ 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;</pre>
+ *
+ * <p><b>Implementation note: this class does not currently contain a
+ * <code>set</code> 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<ServerNameList.ServerName>
+{
+ private ByteBuffer buffer;
+
+ public ServerNameList (final ByteBuffer buffer)
+ {
+ this.buffer = buffer.duplicate().order(ByteOrder.BIG_ENDIAN);
+ }
+
+ public ServerNameList(List<ServerName> 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<ServerName> iterator()
+ {
+ return new Iterator();
+ }
+
+ public class Iterator implements java.util.Iterator<ServerName>
+ {
+ 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;
+
+/**
+ * <pre>
+ struct {
+ select (KeyExchangeAlgorithm) {
+ /* other cases for rsa, diffie_hellman, etc. &ast;/
+ case psk: /* NEW &ast;/
+ opaque psk_identity_hint&lt;0..2^16-1&gt;;
+ };
+ } ServerKeyExchange;</pre>
+ *
+ * @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.
+ *
+ * <pre>
+struct
+{
+ opaque rsa_modulus&lt;1..2^16-1&gt;;
+ opaque rsa_exponent&lt;1..2^16-1&gt;;
+} ServerRSAParams;
+</pre>
+ */
+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.
+ *
+ * <pre>
+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;</pre>
+ */
+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<Session.ID, Session> store;
+ private int storeLimit;
+
+ public SimpleSessionContext()
+ {
+ super(DEFAULT_TIMEOUT);
+ storeLimit = 0;
+ store = new HashMap<Session.ID, Session>();
+ }
+
+ @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<Session.ID, Session> 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<Session.ID> 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.
+ *
+ * <pre>
+struct {
+ TrustedAuthority trusted_authorities_list&lt;0..2^16-1&gt;;
+} 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&lt;1..2^16-1&gt;;</pre>
+ *
+ * @author csm
+ */
+public class TrustedAuthorities extends Value
+ implements Iterable<TrustedAuthorities.TrustedAuthority>
+{
+ 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<TrustedAuthority> iterator()
+ {
+ return new AuthoritiesIterator();
+ }
+
+ public class AuthoritiesIterator implements Iterator<TrustedAuthority>
+ {
+ 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 <code>`hexdump -C'</code>, which is
+ *
+ * <p><pre>OFFSET SIXTEEN-BYTES-IN-HEX PRINTABLE-BYTES</pre>
+ *
+ * <p>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 <i>buffer.length - off</i>, in which case the rest of the
+ * returned byte array will be filled with zeros.
+ * @throws IndexOutOfBoundsException If <i>off</i> or <i>len</i> is
+ * negative, or if <i>off</i> 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 <code>{@link
+ * java.lang.System#currentTimeMillis()} / 1000</code>.
+ *
+ * @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 <i>returnType</i>. For example, the following will transform
+ * array of objects into their String representations, returning a String
+ * array. For example:
+ *
+ * <blockquote><p><code>
+ * String[] strings = (String[]) Util.transform(array, String.class,
+ * "toString", null);
+ * </code></p></blockquote>
+ *
+ * <p>If any element of the given array is <tt>null</tt>, then that
+ * entry in the returned array will also be <tt>null</tt>.
+ *
+ * @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 <i>component</i> 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 <tt>null</tt>
+ * if the method takes no arguments.
+ * @throws InvocationTargetException If an exception occurs while
+ * calling <i>method</i> of any object.
+ * @throws NoSuchMethodException If <i>method</i> 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 <i>args</i> is not appropriate
+ * for <i>method</i>
+ * @throws IllegalAccessException If <i>method</i> is not accessible.
+ * @throws SecurityException If <i>method</i> is not accessible.
+ * @return An array containing the output of <i>method</i> called on
+ * each element of <i>array</i> with <i>args</i>. The return type
+ * of the array will be an array of <i>returnType</i>.
+ */
+ 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 <i>name</i>, 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 <i>name</i>, 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<X500Principal>
+{
+ 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<X500Principal> iterator ()
+ {
+ return new Iterator();
+ }
+
+ public class Iterator implements ListIterator<X500Principal>
+ {
+ 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<X509Certificate[]> chains
+ = ((PrivateCredentials) params).getCertChains();
+ List<PrivateKey> keys
+ = ((PrivateCredentials) params).getPrivateKeys();
+ int i = 0;
+ HashMap<String, X509Certificate[]> certMap
+ = new HashMap<String, X509Certificate[]>();
+ HashMap<String, PrivateKey> keyMap
+ = new HashMap<String, PrivateKey>();
+ Iterator<X509Certificate[]> c = chains.iterator();
+ Iterator<PrivateKey> 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<String, PrivateKey> p = new HashMap<String, PrivateKey>();
+ HashMap<String, X509Certificate[]> c
+ = new HashMap<String, X509Certificate[]>();
+ 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<String, PrivateKey> privateKeys;
+ private final Map<String, X509Certificate[]> certChains;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ Manager(Map<String, PrivateKey> privateKeys,
+ Map<String, X509Certificate[]> 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<String> l = new LinkedList<String>();
+ 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<X509Certificate> l = new LinkedList<X509Certificate>();
+ 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<TrustAnchor> anchors;
+
+ // Constructor.
+ // -----------------------------------------------------------------------
+
+ Manager(X509Certificate[] trusted)
+ {
+ anchors = new HashSet<TrustAnchor>();
+ 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
+ * <p>
+ * See: CUPS Implementation of IPP, chapter 3.2<br>
+ * http://www.cups.org/doc-1.1/ipp.html
+ * </p>
+ *
+ * @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.
+ * <p>
+ * The mapping is used to build up print service specific mappings
+ * for use of media attribute translation between Java JPS API and
+ * CUPS.
+ * </p>
+ *
+ * @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, <code>null</code> 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 <code>CupsPrintService</code> 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
+ * <code>null</code> 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 <code>true</code> if all constraints match, <code>false</code>
+ * 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 <code>true</code> if all constraints match, <code>false</code>
+ * 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;
+
+/**
+ * <code>CupsServer</code> represents a host running a cups
+ * compatible server. It mainly consists of its URI and optional
+ * user and password combination if access is restricted.
+ * <p>
+ * It provides methods for retrival of valid CUPS printer uris
+ * that are used to construct IppPrintService objects.
+ * </p>
+ *
+ * @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 <code>CupsServer</code> object which
+ * tries to connect to a cups server.
+ *
+ * If <code>gnu.javax.print.server</code> 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 <code>CupsServer</code> 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 <code>PrintException</code> further refining the exception
+ * cause by providing an implementation of the print exception
+ * interface <code>AttributeException</code>.
+ *
+ * @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 <code>PrintAttributeException</code>
+ * with the given unsupported attributes and/or values.
+ *
+ * @param unsupportedAttributes the unsupported categories,
+ * may be <code>null</code>.
+ * @param unsupportedValues the unsupported attribute values,
+ * may be <code>null</code>.
+ */
+ public PrintAttributeException(Class[] unsupportedAttributes,
+ Attribute[] unsupportedValues)
+ {
+ super();
+ categories = unsupportedAttributes;
+ values = unsupportedValues;
+ }
+
+ /**
+ * Constructs a <code>PrintAttributeException</code>
+ * with the given unsupported attributes and/or values.
+ *
+ * @param e chained exception
+ * @param unsupportedAttributes the unsupported categories,
+ * may be <code>null</code>.
+ * @param unsupportedValues the unsupported attribute values,
+ * may be <code>null</code>.
+ */
+ public PrintAttributeException(Exception e,
+ Class[] unsupportedAttributes, Attribute[] unsupportedValues)
+ {
+ super(e);
+ categories = unsupportedAttributes;
+ values = unsupportedValues;
+ }
+
+ /**
+ * Constructs a <code>PrintAttributeException</code>
+ * with the given unsupported attributes and/or values.
+ *
+ * @param s detailed message
+ * @param unsupportedAttributes the unsupported categories,
+ * may be <code>null</code>.
+ * @param unsupportedValues the unsupported attribute values,
+ * may be <code>null</code>.
+ */
+ public PrintAttributeException(String s,
+ Class[] unsupportedAttributes, Attribute[] unsupportedValues)
+ {
+ super(s);
+ categories = unsupportedAttributes;
+ values = unsupportedValues;
+ }
+
+ /**
+ * Constructs a <code>PrintAttributeException</code>
+ * with the given unsupported attributes and/or values.
+ *
+ * @param s detailed message
+ * @param e chained exception
+ * @param unsupportedAttributes the unsupported categories,
+ * may be <code>null</code>.
+ * @param unsupportedValues the unsupported attribute values,
+ * may be <code>null</code>.
+ */
+ 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 <code>PrintException</code> further refining the exception
+ * cause by providing an implementation of the print exception
+ * interface <code>FlavorException</code>.
+ *
+ * @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 <code>PrintFlavorException</code>
+ * with the given unsupported doc flavor array
+ *
+ * @param unsupportedFlavors the unsupported document flavors.
+ */
+ public PrintFlavorException(DocFlavor[] unsupportedFlavors)
+ {
+ super();
+ flavors = unsupportedFlavors;
+ }
+
+ /**
+ * Constructs a <code>PrintFlavorException</code>
+ * 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 <code>PrintFlavorException</code>
+ * 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 <code>PrintFlavorException</code>
+ * 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 <code>PrintException</code> further refining the exception
+ * cause by providing an implementation of the print exception
+ * interface <code>URIException</code>.
+ *
+ * @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 <code>PrintUriException</code> 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 <code>PrintUriException</code> 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 <code>PrintUriException</code> 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 <code>PrintUriException</code> 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. <code>null</code> is default screen.
+ * @param services the print services to browse (not null).
+ * @param defaultService the default service. If <code>null</code>
+ * 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. <code>null</code> 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. <code>null</code> is default screen.
+ * @param services the print services to browse (not null).
+ * @param defaultService the default service. If <code>null</code>
+ * 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 <code>IppPrintService</code> 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.
+ * <p>
+ * 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.<br>
+ * 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).
+ * </p>
+ *
+ * @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 <code>true</code> if, <code>false</code> 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;
+
+/**
+ * <code>IppException</code> 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 <code>IppException</code>.
+ */
+ public IppException()
+ {
+ super();
+ }
+
+ /**
+ * Creates an <code>IppException</code>.
+ * @param s the message of the exception.
+ */
+ public IppException(String s)
+ {
+ super(s);
+ }
+
+ /**
+ * Creates an <code>IppException</code>.
+ * @param e the exception cause this one.
+ */
+ public IppException(Exception e)
+ {
+ super(e);
+ }
+
+ /**
+ * Creates an <code>IppException</code>.
+ * @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 <code>IppMultiDocPrintService</code> 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<Class<? extends Attribute>, Set<Attribute>> printerAttr;
+
+ /** The set of listeners.*/
+ private HashSet<PrintServiceAttributeListener> 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<DocFlavor> flavors;
+
+ /** The standard printer URI. */
+ private PrinterURI printerUri;
+
+ /** The list of all supported printer URIs. */
+ private ArrayList<PrinterURI> 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 <code>IppPrintService</code> 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<PrintServiceAttributeListener>();
+
+ 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<Class<? extends Attribute>, Set<Attribute>> 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 <T extends Attribute> Set<T> getPrinterAttributeSet(Class<T> attributeClass)
+ {
+ Set<Attribute> set = printerAttr.get(attributeClass);
+ Set<T> attSet = new HashSet<T>();
+ 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 <code>DefaultValueAttribute</code>.
+ */
+ private Attribute getPrinterDefaultAttribute(Class<? extends Attribute> attributeClass)
+ {
+ Set<Attribute> 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<DocFlavor>();
+ Set<DocumentFormatSupported> 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<PrinterUriSupported> uris = getPrinterAttributeSet(PrinterUriSupported.class);
+ printerUris = new ArrayList<PrinterURI>(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 extends PrintServiceAttribute> T getAttribute(Class<T> 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<T> 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<Attribute> 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<? extends Attribute> 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 <code>PrinterName</code> 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<Class<? extends Attribute>> categories =
+ new HashSet<Class<? extends Attribute>>();
+
+ // 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<FinishingsSupported> 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
+ * <code>handleSupportedAttributeValuesResponse(IppResponse, Class)</code> only.
+ *
+ * @see PrintService#getSupportedAttributeValues(Class, DocFlavor, AttributeSet)
+ * @see #handleSupportedAttributeValuesResponse(IppResponse, Class)
+ */
+ public Object getSupportedAttributeValues(Class<? extends Attribute> 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 <code>null</code> if this print service doesn't support the
+ * given attribute category at all.
+ *
+ * @see #getSupportedAttributeValues(Class, DocFlavor, AttributeSet)
+ */
+ protected Object handleSupportedAttributeValuesResponse(IppResponse response,
+ Class<? extends Attribute> category)
+ {
+ List<Map<Class<? extends Attribute>, Set<Attribute>>> printerAtts =
+ response.getPrinterAttributes();
+
+ // only one will be returned
+ Map<Class<? extends Attribute>, Set<Attribute>> printerAttribute = printerAtts.get(0);
+ Class<? extends Attribute> suppCategory = IppUtilities.getSupportedCategory(category);
+ Set<Attribute> 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<Attribute> 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<Map<Class<? extends Attribute>, Set<Attribute>>> unsupportedMaps =
+ response.getUnsupportedAttributes();
+ if (unsupportedMaps.size() == 0)
+ return null;
+
+ Map<Class<? extends Attribute>, Set<Attribute>> 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<Attribute> unsupported : unsupportedAttr.values())
+ {
+ for (Attribute att : unsupported)
+ set.add(att);
+ }
+
+ return set;
+ }
+
+ /**
+ * @see PrintService#isAttributeCategorySupported(Class)
+ */
+ public boolean isAttributeCategorySupported(Class<? extends Attribute> 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: " + <code>getName()</code>
+ * @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;
+
+/**
+ * <code>IppRequest</code> models a request to an IPP compatible
+ * server as described in RFC 2910 - IPP/1.1: Encoding and Transport.
+ * <p>
+ * The byte stream is structured as follows (for an official description
+ * please have a look at the RFC document mentioned above):
+ * <ul>
+ * <li>version-number - 2 bytes - required</li>
+ * <li>operation-id - 2 bytes - required</li>
+ * <li>request-id - 4 bytes - required</li>
+ * <li>attribute-group - n bytes - 0 or more</li>
+ * <li>end-of-attributes-tag - 1 byte - required</li>
+ * <li>data - q bytes - optional</li>
+ * </ul>
+ * </p>
+ *
+ * @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.
+ * <p>
+ * The syntax value is defined as 11 octets follwing the
+ * DateAndTime format of RFC 1903. (see IppResponse)
+ * </p>
+ *
+ * @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.
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @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 <code>null</code>.
+ */
+ 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 <code>null</code>.
+ */
+ 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;
+
+/**
+ * <code>IppResponse</code> 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
+{
+
+ /**
+ * <code>ResponseReader</code> is responsible for parsing an IPP 1.1
+ * response stream. It provides access to the attribute groups after parsing
+ * via getter methods.
+ * <p>
+ * The enconding of a response is structured as follows (for an official
+ * description please have a look at the RFC document mentioned above):
+ * <ul>
+ * <li>version-number - 2 bytes - required</li>
+ * <li>status-code - 2 bytes - required</li>
+ * <li>request-id - 4 bytes - required</li>
+ * <li>attribute-group - n bytes - 0 or more</li>
+ * <li>end-of-attributes-tag - 1 byte - required</li>
+ * <li>data - q bytes - optional</li>
+ * </ul>
+ * </p><p>
+ * Where each attribute-group (if any) is encoded as follows:
+ * <ul>
+ * <li>begin-attribute-group-tag - 1 byte</li>
+ * <li>attribute - p bytes - 0 or more</li>
+ * </ul>
+ * </p><p>
+ * Encoding of attributes:
+ * <ul>
+ * <li>attribute-with-one-value - q bytes</li>
+ * <li>additional-value - r bytes - 0 or more</li>
+ * </ul>
+ * </p><p>
+ * Encoding of attribute-with-one-value:
+ * <ul>
+ * <li>value-tag - 1 byte</li>
+ * <li>name-length (value is u) - 2 bytes</li>
+ * <li>name - u bytes</li>
+ * <li>value-length (value is v) - 2 bytes</li>
+ * <li>value - v bytes</li>
+ * </ul>
+ * </p><p>
+ * Encoding of additional value:
+ * <ul>
+ * <li>value-tag - 1 byte</li>
+ * <li>name-length (value is 0x0000) - 2 bytes</li>
+ * <li>value-length (value is w) - 2 bytes</li>
+ * <li>value - w bytes</li>
+ * </ul>
+ * </p>
+ *
+ * @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<Class<? extends Attribute>, Set<Attribute>> 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<Class<? extends Attribute>, Set<Attribute>>();
+ tag = parseAttributes(tmp, stream);
+ operationAttributes.add(tmp);
+ break;
+ case IppDelimiterTag.JOB_ATTRIBUTES_TAG:
+ tmp = new HashMap<Class<? extends Attribute>, Set<Attribute>>();
+ tag = parseAttributes(tmp, stream);
+ jobAttributes.add(tmp);
+ break;
+ case IppDelimiterTag.PRINTER_ATTRIBUTES_TAG:
+ tmp = new HashMap<Class<? extends Attribute>, Set<Attribute>>();
+ tag = parseAttributes(tmp, stream);
+ printerAttributes.add(tmp);
+ break;
+ case IppDelimiterTag.UNSUPPORTED_ATTRIBUTES_TAG:
+ System.out.println("Called");
+ tmp = new HashMap<Class<? extends Attribute>, Set<Attribute>>();
+ 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<Class<? extends Attribute>, Set<Attribute>> 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<Class<? extends Attribute>, Set<Attribute>> attributeGroup,
+ Attribute attribute)
+ {
+ Class<? extends Attribute> clazz = attribute.getCategory();
+ Set<Attribute> attributeValues = attributeGroup.get(clazz);
+
+ if (attributeValues == null) // first attribute of this category
+ {
+ attributeValues = new HashSet<Attribute>();
+ 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.
+ * <p>
+ * The syntax value is defined as 11 octets follwing the DateAndTime format
+ * of RFC 1903:
+ * <ul>
+ * <li>field | octets | contents | range</li>
+ * <li>1 | 1-2 | year | 0..65536</li>
+ * <li>2 | 3 | month | 1..12</li>
+ * <li>3 | 4 | day | 1..31</li>
+ * <li>4 | 5 | hour | 0..23</li>
+ * <li>5 | 6 | minutes | 0..59</li>
+ * <li>6 | 7 | seconds | 0..60 (use 60 for leap-second)</li>
+ * <li>7 | 8 | deci-seconds | 0..9</li>
+ * <li>8 | 9 | direction from UTC | '+' / '-'</li>
+ * <li>9 | 10 | hours from UTC | 0..11</li>
+ * <li>10 | 11 | minutes from UTC | 0..59</li>
+ * </ul>
+ * </p>
+ *
+ * @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<Map<Class<? extends Attribute>, Set<Attribute>>> operationAttributes;
+ List<Map<Class<? extends Attribute>, Set<Attribute>>> printerAttributes;
+ List<Map<Class<? extends Attribute>, Set<Attribute>>> jobAttributes;
+ List<Map<Class<? extends Attribute>, Set<Attribute>>> unsupportedAttributes;
+
+ byte[] data;
+
+ /**
+ * Creates an <code>IppResponse</code> 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<Map<Class<? extends Attribute>, Set<Attribute>>>();
+ jobAttributes =
+ new ArrayList<Map<Class<? extends Attribute>, Set<Attribute>>>();
+ printerAttributes =
+ new ArrayList<Map<Class<? extends Attribute>, Set<Attribute>>>();
+ unsupportedAttributes =
+ new ArrayList<Map<Class<? extends Attribute>, Set<Attribute>>>();
+ }
+
+ /**
+ * 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<Map<Class<? extends Attribute>, Set<Attribute>>> 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<Map<Class<? extends Attribute>, Set<Attribute>>> 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<Map<Class<? extends Attribute>, Set<Attribute>>> 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<Map<Class<? extends Attribute>, Set<Attribute>>> 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.
+ * <p>
+ * Also provides mapping from the attribute name values to
+ * the actual class object. Used to construct objects via reflection.
+ * </p>
+ *
+ * @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<String,Class<? extends Attribute>> classesByName =
+ new HashMap<String,Class<? extends Attribute>>();
+ // The map -> StandardAttribute class to SupportedAttribute category name
+ private static HashMap<Class<? extends Attribute>,SupportedValuesAttribute> instanceByClass =
+ new HashMap<Class<? extends Attribute>,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 <code>Class</code> object.
+ */
+ public static Class<? extends Attribute> 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<? extends Attribute> 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<? extends Attribute> getSupportedCategory(Class<? extends Attribute> 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 <code>EnumSyntax</code> 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 <code>IntegerSyntax</code> 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 <code>TextSyntax</code> 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.
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @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 <code>true</code> if, <code>false</code> 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 <code>IppPrintService</code> 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;
+
+/**
+ * <code>CharsetSyntax</code> 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 <code>CharsetSyntax</code> 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 - &gt; Name-default -&gt; 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 <code>DetailedStatusMessage</code> object with the given value
+ * and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>DetailedStatusMessage</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>DocumentAccessError</code> object with the given value
+ * and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>DocumentAccessError</code> itself.
+ */
+ public Class<? extends Attribute> 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;
+
+/**
+ * <code>NaturalLanguageSyntax</code> 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 <code>NaturalLanguageSyntax</code> 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;
+
+/**
+ * <code>RequestedAttributes</code> specifies the requested
+ * attributes in an IPP request operation.
+ *
+ * @author Wolfgang Baer (WBaer@gmx.de)
+ */
+public final class RequestedAttributes implements Attribute
+{
+ private ArrayList<String> attributes;
+
+ /**
+ * Creates a <code>RequestedAttributes</code> 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<String>();
+ 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 <code>DocumentFormat</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>StatusMessage</code> object with the given value
+ * and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>StatusMessage</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>UnknownAttribute</code> 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 <code>UnknownAttribute</code> itself.
+ */
+ public Class<? extends Attribute> 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;
+
+/**
+ * <code>CopiesDefault</code> provides the default value
+ * for the copies attribute.
+ *
+ * @author Wolfgang Baer (WBaer@gmx.de)
+ */
+public final class CopiesDefault extends IntegerSyntax
+ implements DefaultValueAttribute
+{
+
+ /**
+ * Creates a <code>CopiesDefault</code> object.
+ *
+ * @param value the number of copies
+ *
+ * @exception IllegalArgumentException if value &lt; 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 <code>true</code> if both objects are equal,
+ * <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj)
+ {
+ if(! (obj instanceof CopiesDefault))
+ return false;
+
+ return super.equals(obj);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>CopiesDefault</code> itself.
+ */
+ public Class<? extends Attribute> 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.
+ * <p>May return null if no value exists in JPS API.</p>
+ *
+ * @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;
+
+/**
+ * <code>DocumentFormatDefault</code> specifies the default document
+ * format of a printer.
+ *
+ * @author Wolfgang Baer (WBaer@gmx.de)
+ *
+ */
+public final class DocumentFormatDefault extends TextSyntax
+ implements DefaultValueAttribute
+{
+
+ /**
+ * Creates a <code>DocumentFormatDefault</code> object with the
+ * given value and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>DocumentFormatDefault</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>FinishingsDefault</code> 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 <code>FinishingsDefault</code> object.
+ *
+ * @param value the value
+ */
+ protected FinishingsDefault(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return the class <code>FinishingsDefault</code> itself
+ */
+ public Class<? extends Attribute> 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 <code>JobHoldUntilDefault</code> object with the
+ * given value and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>JobHoldUntilDefault</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>JobPriorityDefault</code> object.
+ *
+ * @param value the priority
+ *
+ * @exception IllegalArgumentException if value &lt; 1 or value &gt; 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 <code>true</code> if both objects are equal,
+ * <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj)
+ {
+ if(! (obj instanceof JobPriorityDefault))
+ return false;
+
+ return super.equals(obj);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>JobPriorityDefault</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>JobSheetsDefault</code> object with the
+ * given value and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>JobSheetsDefault</code> itself.
+ */
+ public Class<? extends Attribute> 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.
+ * <p>May return null if no value exists in JPS API.</p>
+ *
+ * @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 <code>MediaDefault</code> object with the
+ * given value and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>MediaDefault</code> itself.
+ */
+ public Class<? extends Attribute> 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;
+
+
+/**
+ * <code>MultipleDocumentHandlingDefault</code> 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 <code>MultipleDocumentHandlingDefault</code> object.
+ *
+ * @param value the enum value
+ */
+ protected MultipleDocumentHandlingDefault(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>MultipleDocumentHandlingDefault</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>NumberUpDefault</code> object.
+ *
+ * @param value the value
+ * @throws IllegalArgumentException if value &lt; 1
+ */
+ public NumberUpDefault(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Tests if the given object is equal to this object.
+ *
+ * @param obj the object to test
+ *
+ * @return <code>true</code> if both objects are equal,
+ * <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj)
+ {
+ if(! (obj instanceof NumberUpDefault))
+ return false;
+
+ return super.equals(obj);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>NumberUpDefault</code> itself.
+ */
+ public Class<? extends Attribute> 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.
+ * <p>May return null if no value exists in JPS API.</p>
+ *
+ * @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 <code>OrientationRequestedDefault</code> 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 <code>OrientationRequestedDefault</code> object.
+ *
+ * @param value the value
+ */
+ protected OrientationRequestedDefault(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>OrientationRequestedDefault</code> itself.
+ */
+ public Class<? extends Attribute> 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;
+
+
+/**
+ * <code>PrintQualityDefault</code> 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 <code>PrintQualityDefault</code> object.
+ *
+ * @param value the value of the enum
+ */
+ protected PrintQualityDefault(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>PrintQualityDefault</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>PrinterResolutionDefault</code> 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 <code>ResolutionSyntax</code> 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 <code>true</code> if both objects are equal,
+ * <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj)
+ {
+ if(! (obj instanceof PrinterResolutionDefault))
+ return false;
+
+ return super.equals(obj);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>PrinterResolutionDefault</code> itself.
+ */
+ public Class<? extends Attribute> 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;
+
+
+/**
+ * <code>SidesDefault</code> 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 <code>SidesDefault</code> object.
+ *
+ * @param value the value of the enum
+ */
+ protected SidesDefault(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>SidesDefault</code> itself.
+ */
+ public Class<? extends Attribute> 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.
+ * <p>
+ * 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.<br>
+ * All clients and IPP objects must support the 'utf-8' charset.
+ * </p>
+ *
+ * @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 <code>AttributesCharset</code> object.
+ *
+ * @param value the charset string value.
+ */
+ public AttributesCharset(String value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>AttributesCharset</code> itself.
+ */
+ public Class<? extends Attribute> 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.
+ * <p>
+ * 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.
+ * </p>
+ *
+ * @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 <code>AttributesNaturalLanguage</code> object.
+ *
+ * @param value the language string value.
+ */
+ public AttributesNaturalLanguage(String value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>AttributesNaturalLanguage</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>JobDetailedStatusMessages</code> object with the given value
+ * and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>JobDetailedStatusMessages</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>JobDocumentAccessErrors</code> object with the given value
+ * and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>JobDocumentAccessErrors</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>JobId</code> 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 <code>IntegerSyntax</code> with the given value.
+ *
+ * @param value the integer to set
+ * @throws IllegalArgumentException if value is &lt; 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 <code>JobId</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>JobMoreInfo</code> 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 <code>JobMoreInfo</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>JobPrinterUri</code> 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 <code>JobPrinterUri</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>JobStateMessage</code> object with the given value
+ * and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>JobStateMessage</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>JobUri</code> 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 <code>JobUri</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>CharsetConfigured</code> object.
+ *
+ * @param value the charset string value.
+ */
+ public CharsetConfigured(String value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>CharsetConfigured</code> itself.
+ */
+ public Class<? extends Attribute> 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;
+
+/**
+ * <code>DocumentFormatSupported</code> 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 <code>DocumentFormat</code> object with the
+ * given value and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>DocumentFormat</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>MultipleOperationTimeOut</code> with the given value.
+ *
+ * @param value the integer to set
+ */
+ public MultipleOperationTimeOut(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>MultipleOperationTimeOut</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>NaturalLanguageConfigured</code> object.
+ *
+ * @param value the charset string value.
+ */
+ public NaturalLanguageConfigured(String value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>NaturalLanguageConfigured</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>PrinterCurrentTime</code> 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 <code>true</code> if both objects are equal,
+ * <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj)
+ {
+ if(! (obj instanceof PrinterCurrentTime))
+ return false;
+
+ return super.equals(obj);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>PrinterCurrentTime</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>PrinterDriverInstaller</code> 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 <code>PrinterDriverInstaller</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>PrinterStateMessage</code> object with the
+ * given value and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>PrinterStateMessage</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>PrinterUpTime</code> with the given value.
+ *
+ * @param value the integer to set
+ */
+ public PrinterUpTime(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>PrinterUpTime</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>CharsetSupported</code> object.
+ *
+ * @param value the charset string value.
+ */
+ public CharsetSupported(String value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>CharsetSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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;
+
+
+/**
+ * <code>CompressionSupported</code> 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 <code>CompressionSupported</code> object.
+ *
+ * @param value the enum value
+ */
+ protected CompressionSupported(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>CompressionSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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<Attribute> 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;
+
+/**
+ * <code>DocumentFormatSupported</code> 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 <code>DocumentFormatSupported</code> object with the
+ * given value and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>DocumentFormatSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>FinishingsSupported</code> 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 <code>FinishingsSupported</code> object.
+ *
+ * @param value the value
+ */
+ protected FinishingsSupported(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return the class <code>FinishingsSupported</code> itself
+ */
+ public Class<? extends Attribute> 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<Attribute> 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 <code>GeneratedNaturalLanguageSupported</code> object.
+ *
+ * @param value the charset string value.
+ */
+ public GeneratedNaturalLanguageSupported(String value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>GeneratedNaturalLanguageSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>IppVersionsSupported</code> object.
+ *
+ * @param value the enum value
+ */
+ public IppVersionsSupported(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns the category of this class.
+ *
+ * @return The class <code>IppVersionsSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>JobHoldUntilSupported</code> object with the
+ * given value and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>JobHoldUntilSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>JobSheetsSupported</code> object with the
+ * given value and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>JobSheetsSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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.
+ * <p>May return null if no value exists in JPS API.</p>
+ *
+ * @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<Attribute> set)
+ {
+ ArrayList<JobSheets> result = new ArrayList<JobSheets>();
+ 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 <code>MediaSupported</code> object with the
+ * given value and locale.
+ *
+ * @param value the value for this syntax
+ * @param locale the locale to use, if <code>null</code> 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 <code>MediaSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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<Attribute> set)
+ {
+ Media tmp2;
+ ArrayList<Media> result = new ArrayList<Media>();
+ 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;
+
+
+/**
+ * <code>MultipleDocumentHandlingSupported</code> 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 <code>MultipleDocumentHandlingSupported</code> object.
+ *
+ * @param value the enum value
+ */
+ protected MultipleDocumentHandlingSupported(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>MultipleDocumentHandlingSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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<Attribute> 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;
+
+/**
+ * <code>MultipleDocumentJobsSupported</code> 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 <code>MultipleDocumentJobsSupported</code> object.
+ *
+ * @param value the enum value
+ */
+ protected MultipleDocumentJobsSupported(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>MultipleDocumentJobsSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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;
+
+/**
+ * <code>OperationsSupported</code> 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 <code>OperationsSupported</code> object.
+ *
+ * @param value the enum value
+ */
+ protected OperationsSupported(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>OperationsSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>OrientationRequestedSupported</code> 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 <code>OrientationRequestedSupported</code> object.
+ *
+ * @param value the value
+ */
+ protected OrientationRequestedSupported(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>OrientationRequestedSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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<Attribute> 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;
+
+/**
+ * <code>PageRangesSupported</code> 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 <code>PageRangesSupported</code> object.
+ *
+ * @param value the enum value
+ */
+ protected PageRangesSupported(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>PageRangesSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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;
+
+
+/**
+ * <code>PrintQualitySupported</code> 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 <code>PrintQualitySupported</code> object.
+ *
+ * @param value the value of the enum
+ */
+ protected PrintQualitySupported(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>PrintQualitySupported</code> itself.
+ */
+ public Class<? extends Attribute> 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<Attribute> 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 <code>PrinterResolutionSupported</code> 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 <code>PrinterResolutionSupported</code> 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 <code>true</code> if both objects are equal,
+ * <code>false</code> otherwise.
+ */
+ public boolean equals(Object obj)
+ {
+ if(! (obj instanceof PrinterResolutionSupported))
+ return false;
+
+ return super.equals(obj);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>PrinterResolutionSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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<Attribute> 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 <code>PrinterUriSupported</code> 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 <code>PrinterUriSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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;
+
+
+/**
+ * <code>SidesSupported</code> 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 <code>SidesSupported</code> object.
+ *
+ * @param value the value of the enum
+ */
+ protected SidesSupported(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>SidesSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>UriAuthenticationSupported</code> object.
+ *
+ * @param value the enum value
+ */
+ public UriAuthenticationSupported(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>UriAuthenticationSupported</code> itself.
+ */
+ public Class<? extends Attribute> 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 <code>UriSecuritySupported</code> object.
+ *
+ * @param value the enum value
+ */
+ public UriSecuritySupported(int value)
+ {
+ super(value);
+ }
+
+ /**
+ * Returns category of this class.
+ *
+ * @return The class <code>UriSecuritySupported</code> itself.
+ */
+ public Class<? extends Attribute> 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
+{
+ /**
+ * <p>
+ * Makes the remote object <code>a_target</code> ready for remote
+ * communication using the same communications runtime as for the passed
+ * <code>a_source</code> 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.<br>
+ * 2. ObjectImpl -> RMI interface.<br>
+ * 3. ObjectImpl -> ObjectImpl.<br>
+ * 4. Tie -> Remote (implementation)<br>
+ * 5. Remote (implementation) -> Tie.<br>
+ *
+ * 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 <code>String</code> 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
+{
+ /**
+ * <p>
+ * 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).
+ * </p>
+ * <p>
+ * 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}.
+ * </p>
+ *
+ * @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".
+ *
+ * <ul>
+ * <li>Try the current thread context class loader first.</li>
+ * <li>If remoteCodebase is non-null and useCodebaseOnly is "false" then call
+ * java.rmi.server.RMIClassLoader.loadClass (remoteCodebase, className)</li>
+ * <li> If remoteCodebase is null or useCodebaseOnly is true then call
+ * java.rmi.server.RMIClassLoader.loadClass(className)</li>
+ * <li>If a class is still not successfully loaded and the loader != null
+ * then try Class.forName(className, false, loader). </li>
+ * </ul>
+ *
+ * @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:
+ * <p>
+ * <table border = "1">
+ * <tr>
+ * <th>CORBA Exception</th>
+ * <th>RMI Exception</th>
+ * </tr>
+ * <tr>
+ * <td>{@link COMM_FAILURE}</td>
+ * <td>{@link MarshalException}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link INV_OBJREF}</td>
+ * <td>{@link NoSuchObjectException}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link NO_PERMISSION}</td>
+ * <td>{@link AccessException}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link MARSHAL}</td>
+ * <td>{@link MarshalException}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link BAD_PARAM} (all other cases)</td>
+ * <td>{@link MarshalException}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link OBJECT_NOT_EXIST}</td>
+ * <td>{@link NoSuchObjectException}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link TRANSACTION_REQUIRED}</td>
+ * <td>{@link TransactionRequiredException}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link TRANSACTION_ROLLEDBACK}</td>
+ * <td>{@link TransactionRolledbackException}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link INVALID_TRANSACTION}</td>
+ * <td>{@link InvalidTransactionException}</td>
+ * </tr>
+ * <tr>
+ * <td bgcolor="lightgray">Any other {@link SystemException}</td>
+ * <td bgcolor="lightgray">{@link RemoteException}</td>
+ * </tr>
+ * </table>
+ * </p>
+ * <p>
+ * The exception detailed message always consists of
+ * <ol>
+ * <li>the string "CORBA "</li>
+ * <li>the CORBA name of the system exception</li>
+ * <li>single space</li>
+ * <li>the hexadecimal value of the system exception's minor code, preceeded
+ * by 0x (higher bits contain {@link OMGVMCID}).</li>
+ * <li>single space</li>
+ * <li>the {@link CompletionStatus} of the exception: "Yes", "No" or "Maybe".</li>
+ * </ol>
+ * <p>
+ * For instance, if the Internet connection was refused:
+ * </p>
+ * <p>
+ * <pre>
+ * <code>CORBA COMM_FAILURE 0x535500C9 No</code>
+ * </p>
+ * <p>
+ * The original CORBA exception is set as the cause of the RemoteException
+ * being created.
+ * </p>
+ */
+ 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: <table border = "1">
+ * <tr>
+ * <th>Exception to map (or subclass)</th>
+ * <th>Maps into</th>
+ * </tr>
+ * <tr>
+ * <td>{@link Error}</td>
+ * <td>{@link ServerError}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link RemoteException}</td>
+ * <td>{@link ServerException}</td>
+ * </tr>
+ * <tr>
+ * <td>{@link SystemException}</td>
+ * <td>wrapException({@link #mapSystemException})</td>
+ * </tr>
+ * <tr>
+ * <td>{@link RuntimeException}</td>
+ * <td><b>rethrows</b></td>
+ * </tr>
+ * <tr>
+ * <td>Any other exception</td>
+ * <td>{@link UnexpectedException}</td>
+ * </tr>
+ * </table>
+ *
+ * @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.
+ *
+ * <p>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, <i>delay</i>.
+ *
+ * @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 <i>password</i> character array parameter element
+ * marking the beginning of the contained password string.
+ * @param length The number of characters, beginning at <i>offset</i>,
+ * 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, <i>delay</i>.
+ *
+ * @param password The character array password to associate with this
+ * Password object.
+ * @param offset The <i>password</i> character array parameter element
+ * marking the beginning of the contained password string.
+ * @param length The number of characters, beginning at <i>offset</i>,
+ * 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, <i>delay</i>.
+ *
+ * @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 <i>password</i> byte array parameter element
+ * marking the beginning of the contained password string.
+ * @param length The number of bytes, beginning at <i>offset</i>,
+ * 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, <i>delay</i>.
+ *
+ * @param password The byte array password to associate with this
+ * Password object.
+ * @param offset The <i>password</i> byte array parameter element
+ * marking the beginning of the contained password string.
+ * @param length The number of bytes, beginning at <i>offset</i>,
+ * 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 <code>CallbackHandler</code> of the designated
+ * <code>type</code> from the first Security Provider which offers it.
+ *
+ * @param type the type of callback handler to create.
+ * @return a newly created instance of <code>ClassbackHandler</code>.
+ * @throws NoSuchAlgorithmException if no security provider is found to offer
+ * an implementation of <code>CallbackHandler</code> of the
+ * designated <code>type</code>.
+ */
+ 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 <code>CallbackHandler</code> of the designated
+ * <code>type</code> from the named security <code>provider</code>.
+ *
+ * @param type the type of callback handler to create.
+ * @param provider a named security provider to use.
+ * @return a newly created instance of <code>ClassbackHandler</code>.
+ * @throws NoSuchAlgorithmException if no security provider is found to offer
+ * an implementation of <code>CallbackHandler</code> of the
+ * designated <code>type</code>.
+ * @throws IllegalArgumentException if either <code>type</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>type</code> 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 <code>CallbackHandler</code> of the designated
+ * <code>type</code> from the designated security <code>provider</code>.
+ *
+ * @param type the type of callback handler to create.
+ * @param provider a security provider to use.
+ * @return a newly created instance of <code>ClassbackHandler</code>.
+ * @throws NoSuchAlgorithmException if no security provider is found to offer
+ * an implementation of <code>CallbackHandler</code> of the
+ * designated <code>type</code>.
+ * @throws IllegalArgumentException if either <code>type</code> or
+ * <code>provider</code> is <code>null</code>, or if
+ * <code>type</code> 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 <code>System.in</code> and <code>System.out</code>.
+ */
+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 <i>default syntax</i> which is interpreted as adhering to
+ * the following grammar:
+ *
+ * <pre>
+ * 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
+ * </pre>
+ *
+ * <p>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.</p>
+ *
+ * <p>In the above context, a JAVA_IDENTIFIER is a sequence of tokens,
+ * separated by the character '.'. Each of these tokens obeys the following:</p>
+ *
+ * <ol>
+ * <li>its first character yields <code>true</code> when used as an input to
+ * the {@link java.lang.Character#isJavaIdentifierStart(char)}, and</li>
+ * <li>all remaining characters, yield <code>true</code> when used as an
+ * input to {@link java.lang.Character#isJavaIdentifierPart(char)}.</li>
+ * </ol>
+ */
+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 <i>default
+ * syntax</i>.
+ *
+ * @param r the {@link Reader} whose contents are assumed to be a JAAS Login
+ * Configuration Module file written in the <i>default syntax</i>.
+ * @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 <code>true</code> if an APP_OR_OTHER_ENTRY was correctly parsed.
+ * Returns <code>false</code> 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 <code>true</code> if a LOGIN_MODULE_ENTRY was correctly parsed.
+ * Returns <code>false</code> 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: <i>"...If a String in the form, ${system.property}, occurs in
+ * the value, it will be expanded to the value of the system property."</i>.
+ * 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.
+ *
+ * <p><b>IMPORTANT</b>: This implementation DOES NOT handle embedded ${}
+ * constructs.
+ *
+ * @param s the raw parameter value, incl. eventually strings of the form
+ * <code>${system.property}</code>.
+ * @return the input string with every occurence of
+ * <code>${system.property}</code> 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 <code>st</code>, when set as
+ * follows:
+ *
+ * <pre>
+ * 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('\'');
+ * </pre>
+ *
+ * <p>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.</p>
+ */
+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 <i>default</i> syntax described in
+ * the publicly available documentation of that class. A more formal definition
+ * of this syntax is as follows:
+ *
+ * <pre>
+ * 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
+ * </pre>
+ *
+ * <p>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:</p>
+ *
+ * <ol>
+ * <li>If the following Security properties:
+ * <i>java.security.auth.login.config.url.<b>N</b></i>, where <i><b>N</b></i>
+ * is a digit, from <code>1</code> 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.
+ *
+ * <p>It is worth noting the following:
+ * <ul>
+ * <li>The GNU Classpath security file, named <i>classpath.security</i>,
+ * where all Security properties are encoded, is usually located in
+ * <i>/usr/local/classpath/lib/security</i> folder.</li>
+ *
+ * <li>The numbers used in the properties
+ * <i>java.security.auth.login.config.url.<b>N</b></i> MUST be sequential,
+ * with no breaks in-between.</li>
+ * </ul>
+ * </p>
+ *
+ * <p>If at least one of the designated Configuration files was found, and
+ * was parsed correctly, then no other location will be inspected.</p></li>
+ *
+ * <li>If the System property named <i>java.security.auth.login.config</i>
+ * is not null or empty, its contents are then interpreted as a URL to a
+ * JAAS Login Configuration file written in the default syntax.
+ *
+ * <p>If this System property is defined, and the file it refers to was
+ * parsed correctly, then no other location will be inspected.</p></li>
+ *
+ * <li>If a file named <i>.java.login.config</i> or <i>java.login.config</i>
+ * (in that order) is found in the location referenced by the value of the
+ * System property <i>user.home</i>, then that file is parsed as a JAAS Login
+ * Configuration written in the default syntax.</li>
+ *
+ * <li>If none of the above resulted in a correctly parsed JAAS Login
+ * Configuration file, then this implementation will install a <i>Null
+ * Configuration</i> which basically does not recognize any Application.</li>
+ * </ol>
+ */
+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 <code>Configuration</code>.
+ *
+ * <p>This method causes this <code>Configuration</code> object to refresh /
+ * reload its contents following the locations and logic described above in
+ * the class documentation section.</p>
+ *
+ * @throws SecurityException if the caller does not have an
+ * {@link AuthPermission} for the action named
+ * <code>refreshLoginConfiguration</code>.
+ * @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
+ * <i>java.security.auth.login.config.url.N</i>.
+ *
+ * @return <code>true</code> if it succeeds, and <code>false</code>
+ * 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 <i>java.security.auth.login.config</i>.
+ *
+ * @return <code>true</code> if it succeeds, and <code>false</code>
+ * 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 <i>.java.login.config</i> or <i>java.login.config</i> (without the
+ * leading dot) in the folder referenced by the System property
+ * <code>user.home</code>.
+ *
+ * @return <code>true</code> if it succeeds, and <code>false</code>
+ * 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 <code>SecurityManager</code>.
+ *
+ * For example, to check for a read permission, a class can simply pass the
+ * <code>Permission.READ</code> constant to
+ * {@link #checkPermissions(gnu.javax.sound.AudioSecurityManager.Permission))},
+ * like the following code demonstrates:
+ *
+ * <pre>
+ * AudioSecurityManager.checkPermissions(Permission.PLAY);
+ * </pre>
+ *
+ * If there is need to query for all the defined permissions type, the constant
+ * <code>Permission.ALL</code> can be used. In alternative, the
+ * {@link #checkPermissions()} is presented as a shorthand.
+ *
+ * @author Mario Torre <neugens@limasoftware.net>
+ */
+public class AudioSecurityManager
+{
+ /**
+ * Defines a common set of permission allowed by the specification.
+ */
+ public static enum Permission
+ {
+ PLAY, RECORD, ALL
+ }
+
+ /**
+ * Shorthand to <code>checkPermissions(Permission.ALL)</code>.
+ */
+ public static final void checkPermissions()
+ {
+ checkPermissions(Permission.ALL);
+ }
+
+ /**
+ * Query the <code>SecurityManager</code> agains the given
+ * <code>Permission</code>.
+ *
+ * @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 <neugens@limasoftware.net>
+ */
+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 <neugens@limasoftware.net>
+ */
+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 <neugens@limasoftware.net>
+ */
+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<String, Object> properties = new HashMap<String, Object>();
+ 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.
+ *
+ * <strong>Note:</strong> 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 <neugens@limasoftware.net>
+ */
+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 <neugens@limasoftware.net>
+ */
+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
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Error.png
Binary files 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
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Inform.png
Binary files 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
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCup.png
Binary files 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
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/JavaCupLarge.png
Binary files 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
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Question.png
Binary files 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
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeClosed.png
Binary files 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
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf-normal.png
Binary files 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
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeLeaf.png
Binary files 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
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/TreeOpen.png
Binary files 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
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/Warn.png
Binary files 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
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/file-folders.png
Binary files 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
--- /dev/null
+++ b/libjava/classpath/gnu/javax/swing/plaf/gtk/icons/slider.png
Binary files 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 <code>true</code> when this is a valid border style,
+ * <code>false</code> 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 <code>true</code> 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 <code>true</code> if the specified value is a valid color value,
+ * <code>false</code> otherwise.
+ *
+ * @param val the value to check
+ *
+ * @return <code>true</code> if the specified value is a valid color value,
+ * <code>false</code> 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 <code>true</code> if the stylesheet could be parsed successfully,
+ * <code>false</code> 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 <code>true</code> if the stylesheet could be parsed successfully,
+ * <code>false</code> otherwise
+ *
+ * @throws IOException if an IO or parse error occurs
+ */
+ private boolean parseStatement()
+ throws IOException
+ {
+ return parseRuleset() || parseAtRule();
+ }
+
+ /**
+ * Parses a CSS rule set.
+ *
+ * @return <code>true</code> if the ruleset could be parsed successfully,
+ * <code>false</code> 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 <code>true</code> if the ruleset could be parsed successfully,
+ * <code>false</code> 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 <code>true</code> if the ruleset could be parsed successfully,
+ * <code>false</code> 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 <code>true</code> if the ruleset could be parsed successfully,
+ * <code>false</code> 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 <code>true</code> if the ruleset could be parsed successfully,
+ * <code>false</code> 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 <code>true</code> if the at-rule could be parsed successfully,
+ * <code>false</code> 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:
+ * <pre>
+ * <selector> {
+ * ... declarations...
+ * }
+ * </pre>
+ *
+ * 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 <code>true</code> when the length value is a percentage
+ * value, <code>false</code> otherwise.
+ *
+ * @return <code>true</code> when the length value is a percentage
+ * value, <code>false</code> otherwise
+ */
+ public boolean isPercentage()
+ {
+ return isPercentage;
+ }
+
+ /**
+ * Checks if the specified value makes up a valid length value.
+ *
+ * @param value the value to check
+ *
+ * @return <code>true</code> 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="<CSS rule>".
+ */
+ 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 <code>true</code> when this selector matches the element path,
+ * <code>false</code> otherwise
+ */
+ public boolean matches(String[] tags, List<Map<String,String>> 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 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in javax.swing.text.html 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 - javax.swing.text.html</title></head>
+
+<body>
+<p> Provides supporting classes for web browsers,
+ web robots, web page content analysers, web editors and
+ other applications applications working with Hypertext
+ Markup Language (HTML).
+</p>
+
+</body>
+</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 &lt;DL&gt; tag:
+ * <code> DT+ | DL+ </code>.
+ * @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 <LI>-</LI> 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;
+
+/**
+ * <p>
+ * 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.</p>
+ *
+ * <p>This implementation also provides you the derived class
+ * <code>gnu.javax.swing.text.html.parser.DTD.HTML_4_0_1</code>, 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. </p>
+ * <p>Use {@link javax.swing.HTML.HTMLEditorKit.Parser#parse }
+ * for parsing in accordance with "-//W3C//DTD HTML 4.01 Frameset//EN"
+ * without specifying DTD separately.</p>
+ *
+ * @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 <code>DTDConstants</code>).
+ * @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 <code>&lt;!ATTLIST </code>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 <code>&amp;lt;</code>
+ * (means '<code>&lt;</code>' );
+ * This method inactivates the recursive refenrences to the same
+ * entity.
+ * @param name The entity name (without heading &amp; 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 <code>next</code>
+ * 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 <b>is</b> 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.*;
+
+/**
+ * <p>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 }
+ * </p>
+ * <p>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 &lt;head&gt; tag: the parser is notified about its silent closing
+ * when &lt;body&gt; 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 <code>list</code>, 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.
+ * <p>@author Audrius Meskauskas, Lithuania (AudriusA@Bioinformatics.org)</p>
+ */
+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 @@
+<!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.models</title></head>
+
+<body>
+<p>This package contains classes for working with content models. In this implementation, the
+standardized content model is pre-processed by <code>transformer</code> into an instance of
+<code>node</code>. Node holds a single element of the content model with the optional unary operation.
+The derived class <code>list</code> holds multiple nodes connected by the same binary operation.
+As the members of this <code>list</code> 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 <code>node</code>.
+</p>
+@author Audrius Meskauskas, Lithuania
+</body>
+</html>
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 @@
+<!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 - javax.swing.text.html.parser</title></head>
+
+<body>
+<p>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.</p>
+@author Audrius Meskauskas, Lithuania
+</body>
+</html>
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;
+
+/**
+ * <p>A simple error-tolerant HTML parser that uses a DTD document
+ * to access data on the possible tokens, arguments and syntax.</p>
+ * <p> 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.</p>
+ * <p>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
+ * <p>&lt;table&gt;&lt;tr&gt;&lt;td&gt;a&lt;td&gt;b&lt;td&gt;c&lt;/tr&gt; <br>
+ * will invoke exactly the handling methods exactly in the same order
+ * (and with the same parameters) as if parsing the document: <br>
+ * <em>&lt;html&gt;&lt;head&gt;&lt;/head&gt;&lt;body&gt;&lt;table&gt;&lt;
+ * tbody&gt;</em>&lt;tr&gt;&lt;td&gt;a<em>&lt;/td&gt;</em>&lt;td&gt;b<em>
+ * &lt;/td&gt;</em>&lt;td&gt;c<em>&lt;/td&gt;&lt;/tr&gt;</em>&lt;
+ * <em>/tbody&gt;&lt;/table&gt;&lt;/body&gt;&lt;/html&gt;</em></p>
+ * (supposed tags are given in italics). The parser also supports
+ * obsolete elements of HTML syntax.<p>
+ * </p>
+ * @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 ( &lt;! ... &gt; ). 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.
+ * <p>
+ * 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) <i>The SGML Handbook</i>,
+ * Oxford University Press, 688 p, ISBN: 0198537379.
+ * </p>
+ * @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 &lt;/html&gt; 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 &lt;br&gt;. 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 &lt;/table&gt;)
+ * 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 &lt;table&gt;)
+ * 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.
+ * <p> 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.
+ * </p>
+ * <p> For pre-formatted text (inside TEXAREA and PRE), the parser preserves
+ * all tabs and spaces, but removes <b>one</b> bounding \r, \n or \r\n,
+ * if it is present. Additionally, it replaces each occurence of \r or \r\n
+ * by a single \n.</p>
+ *
+ * @param text A section text.
+ */
+ protected void handleText(char[] text)
+ {
+ }
+
+ /**
+ * Handle HTML &lt;title&gt; 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 &lt;table&gt;)
+ * 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 &lt;br&gt;. 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 &lt;table&gt;)
+ * 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 <TITLE> 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 ( &lt;/TAG&gt; ).
+ * @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</title></head>
+
+<body>
+<p>This package contains classes that are directly used to process
+the text input: adapted stream tokenizer, specialized buffer and text-level content models .</p>
+@author Audrius Meskauskas, Lithuania
+</body>
+</html>
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 @@
+<!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</title></head>
+
+<body>
+<p>This package provides various specialised classes, needed by HTML parser.
+</p>
+@author Audrius Meskauskas, Lithuania
+</body>
+</html>
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 <code>test</code> 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 &AElig;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 &AElig;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.
+ *
+ * <table border="1" width='100%' cellpadding='3' cellspacing='0'>
+ * <tr bgcolor='#ccccff'>
+ * <th><font size='+1'>Name</font></th>
+ * <th><font size='+1'>Notes</font></th></tr>
+ *
+ * <tr><td colspan=2><center><em>Features ... URL prefix is
+ * <b>http://xml.org/sax/features/</b></em></center></td></tr>
+ *
+ * <tr><td>(URL)/external-general-entities</td>
+ * <td>Value defaults to <em>true</em></td></tr>
+ * <tr><td>(URL)/external-parameter-entities</td>
+ * <td>Value defaults to <em>true</em></td></tr>
+ * <tr><td>(URL)/is-standalone</td>
+ * <td>(PRELIMINARY) Returns true iff the document's parsing
+ * has started (some non-error event after <em>startDocument()</em>
+ * was reported) and the document's standalone flag is set.</td></tr>
+ * <tr><td>(URL)/namespace-prefixes</td>
+ * <td>Value defaults to <em>false</em> (but XML 1.0 names are
+ * always reported)</td></tr>
+ * <tr><td>(URL)/lexical-handler/parameter-entities</td>
+ * <td>Value is fixed at <em>true</em></td></tr>
+ * <tr><td>(URL)/namespaces</td>
+ * <td>Value defaults to <em>true</em></td></tr>
+ * <tr><td>(URL)/resolve-dtd-uris</td>
+ * <td>(PRELIMINARY) Value defaults to <em>true</em></td></tr>
+ * <tr><td>(URL)/string-interning</td>
+ * <td>Value is fixed at <em>true</em></td></tr>
+ * <tr><td>(URL)/use-attributes2</td>
+ * <td>(PRELIMINARY) Value is fixed at <em>true</em></td></tr>
+ * <tr><td>(URL)/use-entity-resolver2</td>
+ * <td>(PRELIMINARY) Value defaults to <em>true</em></td></tr>
+ * <tr><td>(URL)/validation</td>
+ * <td>Value is fixed at <em>false</em></td></tr>
+ *
+ * <tr><td colspan=2><center><em>Handler Properties ... URL prefix is
+ * <b>http://xml.org/sax/properties/</b></em></center></td></tr>
+ *
+ * <tr><td>(URL)/declaration-handler</td>
+ * <td>A declaration handler may be provided. </td></tr>
+ * <tr><td>(URL)/lexical-handler</td>
+ * <td>A lexical handler may be provided. </td></tr>
+ * </table>
+ *
+ * <p>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 &lt;dbrownell@users.sourceforge.net&gt;
+ * @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.
+ //
+
+ /**
+ * <b>SAX1</b>: 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.");
+ }
+
+ /**
+ * <b>SAX2</b>: Returns the object used when resolving external
+ * entities during parsing (both general and parameter entities).
+ */
+ public EntityResolver getEntityResolver()
+ {
+ return (entityResolver == base) ? null : entityResolver;
+ }
+
+ /**
+ * <b>SAX1, SAX2</b>: 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;
+ }
+
+ /**
+ * <b>SAX2</b>: Returns the object used to process declarations related
+ * to notations and unparsed entities.
+ */
+ public DTDHandler getDTDHandler()
+ {
+ return (dtdHandler == base) ? null : dtdHandler;
+ }
+
+ /**
+ * <b>SAX1, SAX2</b>: 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;
+ }
+
+
+ /**
+ * <b>SAX1</b>: 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;
+ }
+
+ /**
+ * <b>SAX2</b>: Returns the object used to report the logical
+ * content of an XML document.
+ */
+ public ContentHandler getContentHandler()
+ {
+ return (contentHandler == base) ? null : contentHandler;
+ }
+
+ /**
+ * <b>SAX2</b>: 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;
+ }
+
+ /**
+ * <b>SAX1, SAX2</b>: 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;
+ }
+
+ /**
+ * <b>SAX2</b>: 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;
+ }
+
+ /**
+ * <b>SAX1, SAX2</b>: 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();
+ }
+ }
+ }
+
+ /**
+ * <b>SAX1, SAX2</b>: 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/";
+
+ /**
+ * <b>SAX2</b>: 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;
+ }
+
+ /**
+ * <b>SAX2</b>: 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);
+ }
+
+ /**
+ * <b>SAX2</b>: 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);
+ }
+
+ /**
+ * <b>SAX2</b>: 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.
+ //
+
+ /**
+ * <b>SAX1 AttributeList, SAX2 Attributes</b> method
+ * (don't invoke on parser);
+ */
+ public int getLength()
+ {
+ return attributesList.size();
+ }
+
+ /**
+ * <b>SAX2 Attributes</b> 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;
+ }
+
+ /**
+ * <b>SAX2 Attributes</b> 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;
+ }
+
+ /**
+ * <b>SAX2 Attributes</b> 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;
+ }
+
+ /**
+ * <b>SAX1 AttributeList</b> method (don't invoke on parser);
+ */
+ public String getName(int index)
+ {
+ return getQName(index);
+ }
+
+ /**
+ * <b>SAX1 AttributeList, SAX2 Attributes</b> 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;
+ }
+
+ /**
+ * <b>SAX1 AttributeList, SAX2 Attributes</b> 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;
+ }
+
+ /**
+ * <b>SAX2 Attributes</b> 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;
+ }
+
+ /**
+ * <b>SAX2 Attributes</b> 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;
+ }
+
+ /**
+ * <b>SAX2 Attributes</b> 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);
+ }
+
+ /**
+ * <b>SAX1 AttributeList, SAX2 Attributes</b> method
+ * (don't invoke on parser);
+ */
+ public String getType(String xmlName)
+ {
+ int index = getIndex(xmlName);
+
+ if (index < 0)
+ {
+ return null;
+ }
+ return getType(index);
+ }
+
+ /**
+ * <b>SAX Attributes</b> 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);
+ }
+
+ /**
+ * <b>SAX1 AttributeList, SAX2 Attributes</b> 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);
+ }
+
+ /**
+ * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
+ */
+ public boolean isSpecified(int index)
+ {
+ return ((Attribute) attributesList.get(index)).specified;
+ }
+
+ /**
+ * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
+ */
+ public boolean isSpecified(String uri, String local)
+ {
+ int index = getIndex (uri, local);
+ return isSpecified(index);
+ }
+
+ /**
+ * <b>SAX-ext Attributes2</b> method (don't invoke on parser);
+ */
+ public boolean isSpecified(String xmlName)
+ {
+ int index = getIndex (xmlName);
+ return isSpecified(index);
+ }
+
+ //
+ // Implementation of org.xml.sax.Locator.
+ //
+
+ /**
+ * <b>SAX Locator</b> method (don't invoke on parser);
+ */
+ public String getPublicId()
+ {
+ return null; // FIXME track public IDs too
+ }
+
+ /**
+ * <b>SAX Locator</b> method (don't invoke on parser);
+ */
+ public String getSystemId()
+ {
+ if (entityStack.empty())
+ {
+ return null;
+ }
+ else
+ {
+ return (String) entityStack.peek();
+ }
+ }
+
+ /**
+ * <b>SAX Locator</b> method (don't invoke on parser);
+ */
+ public int getLineNumber()
+ {
+ return parser.getLineNumber();
+ }
+
+ /**
+ * <b>SAX Locator</b> 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 <code>SAXDriver</code> class as your entry point, as all
+ * internal parser interfaces are subject to change.
+ *
+ * @author Written by David Megginson &lt;dmeggins@microstar.com&gt;
+ * (version 1.2a with bugfixes)
+ * @author Updated by David Brownell &lt;dbrownell@users.sourceforge.net&gt;
+ * @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.
+ *
+ * <p> 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 <em>or</em> 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", "&#38;");
+ setInternalEntity("lt", "&#60;");
+ setInternalEntity("gt", "&#62;");
+ setInternalEntity("apos", "&#39;");
+ setInternalEntity("quot", "&#34;");
+
+ 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.
+ * <pre>
+ * [1] document ::= prolog element Misc*
+ * </pre>
+ * <p>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.
+ * <pre>
+ * [15] Comment ::= '&lt;!--' ((Char - '-') | ('-' (Char - '-')))* "-->"
+ * </pre>
+ * <p> (The <code>&lt;!--</code> 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.
+ * <pre>
+ * [16] PI ::= '&lt;?' PITarget
+ * (S (Char* - (Char* '?&gt;' Char*)))?
+ * '?&gt;'
+ * [17] PITarget ::= Name - ( ('X'|'x') ('M'|m') ('L'|l') )
+ * </pre>
+ * <p> (The <code>&lt;?</code> 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.
+ * <pre>
+ * [18] CDSect ::= CDStart CData CDEnd
+ * [19] CDStart ::= '&lt;![CDATA['
+ * [20] CData ::= (Char* - (Char* ']]&gt;' Char*))
+ * [21] CDEnd ::= ']]&gt;'
+ * </pre>
+ * <p> (The '&lt;![CDATA[' has already been read.)
+ */
+ private void parseCDSect()
+ throws Exception
+ {
+ parseUntil(endDelimCDATA);
+ dataBufferFlush();
+ }
+
+ /**
+ * Parse the prolog of an XML document.
+ * <pre>
+ * [22] prolog ::= XMLDecl? Misc* (Doctypedecl Misc*)?
+ * </pre>
+ * <p>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("<!DOCTYPE"))
+ {
+ parseDoctypedecl();
+ parseMisc();
+ return true;
+ }
+ return false;
+ }
+
+ private void checkLegalVersion(String version)
+ throws SAXException
+ {
+ int len = version.length();
+ for (int i = 0; i < len; i++)
+ {
+ char c = version.charAt(i);
+ if ('0' <= c && c <= '9')
+ {
+ continue;
+ }
+ if (c == '_' || c == '.' || c == ':' || c == '-')
+ {
+ continue;
+ }
+ if ('a' <= c && c <= 'z')
+ {
+ continue;
+ }
+ if ('A' <= c && c <= 'Z')
+ {
+ continue;
+ }
+ error ("illegal character in version", version, "1.0");
+ }
+ }
+
+ /**
+ * Parse the XML declaration.
+ * <pre>
+ * [23] XMLDecl ::= '&lt;?xml' VersionInfo EncodingDecl? SDDecl? S? '?&gt;'
+ * [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._] | '-')*
+ * </pre>
+ * <p> (The <code>&lt;?xml</code> 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.
+ * <pre>
+ * [79] TextDecl ::= '&lt;?xml' VersionInfo? EncodingDecl S? '?&gt;'
+ * [80] EncodingDecl ::= S 'encoding' Eq
+ * ( '"' EncName '"' | "'" EncName "'" )
+ * [81] EncName ::= [A-Za-z] ([A-Za-z0-9._] | '-')*
+ * </pre>
+ * <p> (The <code>&lt;?xml</code>' 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).
+ *
+ * <p> 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.
+ * <pre>
+ * [27] Misc ::= Comment | PI | S
+ * </pre>
+ */
+ private void parseMisc()
+ throws Exception
+ {
+ while (true)
+ {
+ skipWhitespace();
+ if (tryRead(startDelimPI))
+ {
+ parsePI();
+ }
+ else if (tryRead(startDelimComment))
+ {
+ parseComment();
+ }
+ else
+ {
+ return;
+ }
+ }
+ }
+
+ /**
+ * Parse a document type declaration.
+ * <pre>
+ * [28] doctypedecl ::= '&lt;!DOCTYPE' S Name (S ExternalID)? S?
+ * ('[' (markupdecl | PEReference | S)* ']' S?)? '&gt;'
+ * </pre>
+ * <p> (The <code>&lt;!DOCTYPE</code> 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.
+ * <pre>
+ * [29] markupdecl ::= elementdecl | Attlistdecl | EntityDecl
+ * | NotationDecl | PI | Comment
+ * [30] extSubsetDecl ::= (markupdecl | conditionalSect
+ * | PEReference | S) *
+ * </pre>
+ * <p> 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("<!ELEMENT"))
+ {
+ saved = readBuffer;
+ expandPE = savedPE;
+ parseElementDecl();
+ }
+ else if (tryRead("<!ATTLIST"))
+ {
+ saved = readBuffer;
+ expandPE = savedPE;
+ parseAttlistDecl();
+ }
+ else if (tryRead("<!ENTITY"))
+ {
+ saved = readBuffer;
+ expandPE = savedPE;
+ parseEntityDecl();
+ }
+ else if (tryRead("<!NOTATION"))
+ {
+ saved = readBuffer;
+ expandPE = savedPE;
+ parseNotationDecl();
+ }
+ else if (tryRead(startDelimPI))
+ {
+ saved = readBuffer;
+ expandPE = savedPE;
+ parsePI();
+ }
+ else if (tryRead(startDelimComment))
+ {
+ saved = readBuffer;
+ expandPE = savedPE;
+ parseComment();
+ }
+ else if (tryRead("<!["))
+ {
+ saved = readBuffer;
+ expandPE = savedPE;
+ if (inputStack.size() > 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.
+ * <pre>
+ * [39] element ::= EmptyElementTag | STag content ETag
+ * [40] STag ::= '&lt;' Name (S Attribute)* S? '&gt;'
+ * [44] EmptyElementTag ::= '&lt;' Name (S Attribute)* S? '/&gt;'
+ * </pre>
+ * <p> (The '&lt;' has already been read.)
+ * <p>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.
+ * <pre>
+ * [41] Attribute ::= Name Eq AttValue
+ * </pre>
+ * @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.
+ * <pre>
+ * [25] Eq ::= S? '=' S?
+ * </pre>
+ */
+ private void parseEq()
+ throws SAXException, IOException
+ {
+ skipWhitespace();
+ require('=');
+ skipWhitespace();
+ }
+
+ /**
+ * Parse an end tag.
+ * <pre>
+ * [42] ETag ::= '</' Name S? '>'
+ * </pre>
+ * <p>NOTE: parseContent () chains to here, we already read the
+ * "&lt;/".
+ */
+ 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.
+ * <pre>
+ * [43] content ::= (element | CharData | Reference
+ * | CDSect | PI | Comment)*
+ * [67] Reference ::= EntityRef | CharRef
+ * </pre>
+ * <p> 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 "<!"
+ c = readCh();
+ switch (c)
+ {
+ case '-': // Found "<!-"
+ require('-');
+ isDirtyCurrentElement = false;
+ parseComment();
+ break;
+ case '[': // Found "<!["
+ isDirtyCurrentElement = false;
+ require("CDATA[");
+ handler.startCDATA();
+ inCDATA = true;
+ parseCDSect();
+ inCDATA = false;
+ handler.endCDATA();
+ break;
+ default:
+ error("expected comment or CDATA section", c, null);
+ break;
+ }
+ break;
+
+ case '?': // Found "<?"
+ isDirtyCurrentElement = false;
+ parsePI();
+ break;
+
+ case '/': // Found "</"
+ isDirtyCurrentElement = false;
+ parseETag();
+ return;
+
+ default: // Found "<" followed by something else
+ isDirtyCurrentElement = false;
+ unread(c);
+ parseElement(false);
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Parse an element type declaration.
+ * <pre>
+ * [45] elementdecl ::= '&lt;!ELEMENT' S Name S contentspec S? '&gt;'
+ * </pre>
+ * <p> NOTE: the '&lt;!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.
+ * <pre>
+ * [46] contentspec ::= 'EMPTY' | 'ANY' | Mixed | elements
+ * </pre>
+ */
+ 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.
+ * <pre>
+ * [47] elements ::= (choice | seq) ('?' | '*' | '+')?
+ * [49] choice ::= '(' S? cp (S? '|' S? cp)+ S? ')'
+ * [50] seq ::= '(' S? cp (S? ',' S? cp)* S? ')'
+ * </pre>
+ *
+ * <p> 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.
+ * <pre>
+ * [48] cp ::= (Name | choice | seq) ('?' | '*' | '+')?
+ * </pre>
+ */
+ 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.
+ * <pre>
+ * [51] Mixed ::= '(' S? ( '#PCDATA' (S? '|' S? Name)*) S? ')*'
+ * | '(' S? ('#PCDATA') S? ')'
+ * </pre>
+ *
+ * @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.
+ * <pre>
+ * [52] AttlistDecl ::= '&lt;!ATTLIST' S Name AttDef* S? '&gt;'
+ * </pre>
+ * <p>NOTE: the '&lt;!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.
+ * <pre>
+ * [53] AttDef ::= S Name S AttType S DefaultDecl
+ * </pre>
+ */
+ 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.
+ * <pre>
+ * [54] AttType ::= StringType | TokenizedType | EnumeratedType
+ * [55] StringType ::= 'CDATA'
+ * [56] TokenizedType ::= 'ID' | 'IDREF' | 'IDREFS' | 'ENTITY'
+ * | 'ENTITIES' | 'NMTOKEN' | 'NMTOKENS'
+ * [57] EnumeratedType ::= NotationType | Enumeration
+ * </pre>
+ */
+ 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.
+ * <pre>
+ * [59] Enumeration ::= '(' S? Nmtoken (S? '|' S? Nmtoken)* S? ')'
+ * </pre>
+ * <p>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.
+ * <pre>
+ * [58] NotationType ::= 'NOTATION' S '(' S? NameNtoks
+ * (S? '|' S? name)* S? ')'
+ * </pre>
+ * <p>NOTE: the 'NOTATION' has already been read
+ */
+ private void parseNotationType()
+ throws Exception
+ {
+ requireWhitespace();
+ require('(');
+
+ parseEnumeration(true);
+ }
+
+ /**
+ * Parse the default value for an attribute.
+ * <pre>
+ * [60] DefaultDecl ::= '#REQUIRED' | '#IMPLIED'
+ * | (('#FIXED' S)? AttValue)
+ * </pre>
+ */
+ 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.
+ * <pre>
+ * [61] conditionalSect ::= includeSect || ignoreSect
+ * [62] includeSect ::= '&lt;![' S? 'INCLUDE' S? '['
+ * extSubsetDecl ']]&gt;'
+ * [63] ignoreSect ::= '&lt;![' S? 'IGNORE' S? '['
+ * ignoreSectContents* ']]&gt;'
+ * [64] ignoreSectContents ::= Ignore
+ * ('&lt;![' ignoreSectContents* ']]&gt;' Ignore )*
+ * [65] Ignore ::= Char* - (Char* ( '&lt;![' | ']]&gt;') Char* )
+ * </pre>
+ * <p> NOTE: the '&gt;![' 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.
+ * <pre>
+ * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
+ * </pre>
+ * <p>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.
+ * <pre>
+ * [66] CharRef ::= '&#' [0-9]+ ';' | '&#x' [0-9a-fA-F]+ ';'
+ * </pre>
+ * <p>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.
+ * <pre>
+ * [68] EntityRef ::= '&' Name ';'
+ * </pre>
+ * <p>NOTE: the '&amp;' 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.
+ * <pre>
+ * [69] PEReference ::= '%' Name ';'
+ * </pre>
+ * <p>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.
+ * <pre>
+ * [70] EntityDecl ::= GEDecl | PEDecl
+ * [71] GEDecl ::= '&lt;!ENTITY' S Name S EntityDef S? '&gt;'
+ * [72] PEDecl ::= '&lt;!ENTITY' S '%' S Name S PEDef S? '&gt;'
+ * [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
+ * </pre>
+ * <p>NOTE: the '&lt;!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.
+ * <pre>
+ * [82] NotationDecl ::= '&lt;!NOTATION' S Name S
+ * (ExternalID | PublicID) S? '&gt;'
+ * [83] PublicID ::= 'PUBLIC' S PubidLiteral
+ * </pre>
+ * <P>NOTE: the '&lt;!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.
+ * <pre>
+ * [14] CharData ::= [^&lt;&amp;]* - ([^&lt;&amp;]* ']]&gt;' [^&lt;&amp;]*)
+ * </pre>
+ */
+ 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.
+ * <pre>
+ * [3] S ::= (#x20 | #x9 | #xd | #xa)+
+ * </pre>
+ */
+ 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.
+ * <pre>
+ * [5] Name ::= (Letter | '_' | ':') (NameChar)*
+ * [7] Nmtoken ::= (NameChar)+
+ * </pre>
+ */
+ 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:
+ * <pre>
+ * [9] EntityValue ::= ... ([^%&amp;] | PEReference | Reference)* ...
+ * [10] AttValue ::= ... ([^<&] | Reference)* ...
+ * [11] SystemLiteral ::= ... (URLchar - "'")* ...
+ * [12] PubidLiteral ::= ... (PubidChar - "'")* ...
+ * </pre>
+ * 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("&#38;"))
+ {
+ 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.
+ * <pre>
+ * [3] S ::= (#x20 | #x9 | #xd | #xa)+
+ * </pre>
+ * @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.
+ * <p><em>Precondition:</em> Entity expansion is not required.
+ * <p><em>Precondition:</em> 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.
+ * &AElig;lfred uses this method to create an interned version
+ * of all names and name tokens, so that it can test equality
+ * with <code>==</code> instead of <code>String.equals ()</code>.
+ *
+ * <p>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 <!ELEMENT ...> or <!ATTLIST ...> for this type?
+ if (element == null)
+ {
+ element = new ElementDecl();
+ element.contentType = contentType;
+ element.contentModel = contentModel;
+ element.attributes = attributes;
+ elementInfo.put(name, element);
+ return;
+ }
+
+ // <!ELEMENT ...> declaration?
+ if (contentType != CONTENT_UNDECLARED)
+ {
+ // ... following an associated <!ATTLIST ...>
+ 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 <!ATTLIST ...>, before <!ELEMENT ...> ?
+ 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.
+ * <p>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 <!ELEMENT ...>
+ 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.
+ * <p>The readDataChunk () method maintains the buffer.
+ * <p>If we hit the end of an entity, try to pop the stack and
+ * keep going.
+ * <p> (This approach doesn't really enforce XML's rules about
+ * entity boundaries, but this is not currently a validating
+ * parser).
+ * <p>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.
+ * <p>This method usually pushes the character back onto
+ * the readBuffer.
+ * <p>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.
+ * <p>NOTE: you must <em>never</em> 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).
+ *
+ * <p> 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("<?xml"))
+ {
+ if (tryWhitespace())
+ {
+ if (inputStack.size() > 0)
+ {
+ return parseTextDecl(ignoreEncoding);
+ }
+ else
+ {
+ return parseXMLDecl(ignoreEncoding);
+ }
+ }
+ else
+ {
+ // <?xml-stylesheet ...?> or similar
+ unread('l');
+ unread('m');
+ unread('x');
+ unread('?');
+ unread('<');
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Attempt to detect the encoding of an entity.
+ * <p>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,
+ * <b>must</b> begin with an XML declaration or an encoding
+ * declaration; we simply have to look for "&lt;?xml" in various
+ * encodings.
+ * <p>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 "<?xml"
+ // 0x00 0x00 0x00 0x3c: UCS-4, big-endian (1234)
+ // "UTF-32BE"
+ encoding = ENCODING_UCS_4_1234;
+ }
+ else if (tryEncoding(signature, (byte) 0x3c, (byte) 0x00,
+ (byte) 0x00, (byte) 0x00))
+ {
+ // 0x3c 0x00 0x00 0x00: UCS-4, little-endian (4321)
+ // "UTF-32LE"
+ encoding = ENCODING_UCS_4_4321;
+ }
+ else if (tryEncoding(signature, (byte) 0x00, (byte) 0x00,
+ (byte) 0x3c, (byte) 0x00))
+ {
+ // 0x00 0x00 0x3c 0x00: UCS-4, unusual (2143)
+ encoding = ENCODING_UCS_4_2143;
+ }
+ else if (tryEncoding(signature, (byte) 0x00, (byte) 0x3c,
+ (byte) 0x00, (byte) 0x00))
+ {
+ // 0x00 0x3c 0x00 0x00: UCS-4, unusual (3421)
+ encoding = ENCODING_UCS_4_3412;
+
+ // 00 00 fe ff UCS_4_1234 (with BOM)
+ // ff fe 00 00 UCS_4_4321 (with BOM)
+ }
+
+ //
+ // SECOND: two byte encodings
+ // note ... with 1/14/2000 errata the XML spec identifies some
+ // more "broken UTF-16" autodetection cases, with no XML decl,
+ // which we don't handle here (that's legal too).
+ //
+ else if (tryEncoding(signature, (byte) 0xfe, (byte) 0xff))
+ {
+ // UCS-2 with a byte-order marker. (UTF-16)
+ // 0xfe 0xff: UCS-2, big-endian (12)
+ encoding = ENCODING_UCS_2_12;
+ is.read(); is.read();
+ }
+ else if (tryEncoding(signature, (byte) 0xff, (byte) 0xfe))
+ {
+ // UCS-2 with a byte-order marker. (UTF-16)
+ // 0xff 0xfe: UCS-2, little-endian (21)
+ encoding = ENCODING_UCS_2_21;
+ is.read(); is.read();
+ }
+ else if (tryEncoding(signature, (byte) 0x00, (byte) 0x3c,
+ (byte) 0x00, (byte) 0x3f))
+ {
+ // UTF-16BE (otherwise, malformed UTF-16)
+ // 0x00 0x3c 0x00 0x3f: UCS-2, big-endian, no byte-order mark
+ encoding = ENCODING_UCS_2_12;
+ error("no byte-order mark for UCS-2 entity");
+ }
+ else if (tryEncoding(signature, (byte) 0x3c, (byte) 0x00,
+ (byte) 0x3f, (byte) 0x00))
+ {
+ // UTF-16LE (otherwise, malformed UTF-16)
+ // 0x3c 0x00 0x3f 0x00: UCS-2, little-endian, no byte-order mark
+ encoding = ENCODING_UCS_2_21;
+ error("no byte-order mark for UCS-2 entity");
+ }
+
+ //
+ // THIRD: ASCII-derived encodings, fixed and variable lengths
+ //
+ else if (tryEncoding(signature, (byte) 0x3c, (byte) 0x3f,
+ (byte) 0x78, (byte) 0x6d))
+ {
+ // ASCII derived
+ // 0x3c 0x3f 0x78 0x6d: UTF-8 or other 8-bit markup (read ENCODING)
+ encoding = ENCODING_UTF_8;
+ prefetchASCIIEncodingDecl();
+ }
+ else if (signature[0] == (byte) 0xef
+ && signature[1] == (byte) 0xbb
+ && signature[2] == (byte) 0xbf)
+ {
+ // 0xef 0xbb 0xbf: UTF-8 BOM (not part of document text)
+ // this un-needed notion slipped into XML 2nd ed through a
+ // "non-normative" erratum; now required by MSFT and UDDI,
+ // and E22 made it normative.
+ encoding = ENCODING_UTF_8;
+ is.read(); is.read(); is.read();
+ }
+ else
+ {
+ // 4c 6f a7 94 ... we don't understand EBCDIC flavors
+ // ... but we COULD at least kick in some fixed code page
+
+ // (default) UTF-8 without encoding/XML declaration
+ encoding = ENCODING_UTF_8;
+ }
+ }
+
+ /**
+ * Check for a four-byte signature.
+ * <p>Utility routine for detectEncoding ().
+ * <p>Always looks for some part of "<?XML" in a specific encoding.
+ * @param sig The first four bytes read.
+ * @param b1 The first byte of the signature
+ * @param b2 The second byte of the signature
+ * @param b3 The third byte of the signature
+ * @param b4 The fourth byte of the signature
+ * @see #detectEncoding
+ */
+ private static boolean tryEncoding(byte[] sig, byte b1, byte b2,
+ byte b3, byte b4)
+ {
+ return (sig[0] == b1 && sig[1] == b2
+ && sig[2] == b3 && sig[3] == b4);
+ }
+
+ /**
+ * Check for a two-byte signature.
+ * <p>Looks for a UCS-2 byte-order mark.
+ * <p>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.
+ * <p>It is useful either as the expansion of an internal entity,
+ * or for backtracking during the parse.
+ * <p>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.
+ * <p>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.
+ * <p>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.
+ * <p>The method saves the following global variables onto a stack
+ * using a fixed-length array:
+ * <ol>
+ * <li>sourceType
+ * <li>externalEntity
+ * <li>readBuffer
+ * <li>readBufferPos
+ * <li>readBufferLength
+ * <li>line
+ * <li>encoding
+ * </ol>
+ * @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.
+ * <p>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.
+ * <p>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.
+ * <p>This is simply a convenience method.
+ * <p>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.
+ * <p>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.
+ * <p>This is simply a convenience method.
+ * <p>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.
+ * <p>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.
+ * <p>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.
+ * <p>When readDataChunk () calls this method, the raw bytes are in
+ * rawReadBuffer, and the final characters will appear in
+ * readBuffer.
+ * <p>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.
+ *
+ * <p>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).
+ *
+ * <p>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.
+ *
+ * <p>When readDataChunk () calls this method, the raw bytes are in
+ * rawReadBuffer, and the final characters will appear in
+ * readBuffer.
+ * <p>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 &AElig;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.
+ * (&AElig;lfred2 tests some of those, even in non-validating mode, to
+ * achieve better conformance.)
+ *
+ * <p> 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());
+ }
+ }
+
+ /**
+ * <b>SAX2</b>: Returns the object used to report the logical
+ * content of an XML document.
+ */
+ public ContentHandler getContentHandler()
+ {
+ return filter.getContentHandler();
+ }
+
+ /**
+ * <b>SAX2</b>: 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);
+ }
+
+ /**
+ * <b>SAX2</b>: Returns the object used to process declarations related
+ * to notations and unparsed entities.
+ */
+ public DTDHandler getDTDHandler()
+ {
+ return filter.getDTDHandler();
+ }
+
+ /**
+ * <b>SAX1</b> Assigns DTD handler
+ * @exception IllegalStateException if called mid-parse
+ */
+ public void setDTDHandler(DTDHandler handler)
+ {
+ if (active)
+ {
+ throw new IllegalStateException("already parsing");
+ }
+ filter.setDTDHandler(handler);
+ }
+
+ /**
+ * <b>SAX2</b>: Returns the object used when resolving external
+ * entities during parsing (both general and parameter entities).
+ */
+ public EntityResolver getEntityResolver()
+ {
+ return aelfred2.getEntityResolver();
+ }
+
+ /**
+ * <b>SAX1</b> Assigns parser's entity resolver
+ */
+ public void setEntityResolver(EntityResolver handler)
+ {
+ aelfred2.setEntityResolver(handler);
+ }
+
+ /**
+ * <b>SAX2</b>: 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();
+ }
+
+ /**
+ * <b>SAX1</b> Assigns error handler
+ * @exception IllegalStateException if called mid-parse
+ */
+ public void setErrorHandler(ErrorHandler handler)
+ {
+ if (active)
+ {
+ throw new IllegalStateException("already parsing");
+ }
+ aelfred2.setErrorHandler(handler);
+ }
+
+ /**
+ * <b>SAX2</b>: 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);
+ }
+ }
+
+ /**
+ * <b>SAX2</b>: 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);
+ }
+
+ /**
+ * <b>SAX2</b>: 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);
+ }
+ }
+
+ /**
+ * <b>SAX2</b>: 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);
+ }
+
+ /**
+ * <b>SAX1</b>: 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);
+ }
+
+ /**
+ * <b>SAX1</b>: Preferred API to parse an XML document, using a
+ * system identifier (URI).
+ */
+ public void parse(String systemId)
+ throws SAXException, IOException
+ {
+ parse(new InputSource(systemId));
+ }
+
+ /**
+ * <b>SAX1</b>: 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 @@
+<!DOCTYPE html PUBLIC
+ '-//W3C//DTD XHTML 1.0 Transitional//EN'
+ 'http://www.w3.org/TR/xhtml1/DTD/transitional.dtd'>
+
+<html><head>
+ <title>package overview</title>
+<!--
+/*
+ * Copyright (C) 1999,2000,2001 The Free Software Foundation, Inc.
+ */
+-->
+</head><body>
+
+<p> This package contains &AElig;lfred2, which includes an
+enhanced SAX2-compatible version of the &AElig;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. </p>
+
+<ul>
+ <li><a href="#about">About &AElig;lfred</a><ul>
+ <li><a href="#principles">Design Principles</a></li>
+ <li><a href="#name">About the Name &AElig;lfred</a></li>
+ <li><a href="#encodings">Character Encodings</a></li>
+ <li><a href="#violations">Known Conformance Violations</a></li>
+ <li><a href="#copyright">Licensing</a></li>
+ </ul></li>
+
+ <li><a href="#changes">Changes Since the Last Microstar Release</a><ul>
+ <li><a href="#sax2">SAX2 Support</a></li>
+ <li><a href="#validation">Validation</a></li>
+ <li><a href="#smaller">You Want Smaller?</a></li>
+ <li><a href="#bugfixes">Bugs Fixed</a></li>
+ </ul></li>
+
+</ul>
+
+<h2><a name="about">About &AElig;lfred</a></h2>
+
+<p>&AElig;lfred is a XML parser written in the java programming language.
+
+<h3><a name="principles">Design Principles</a></h3>
+
+<p>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.</p>
+
+<p> 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. </p>
+
+<p> &AElig;lfred is designed for easy and efficient use over the Internet,
+based on the following principles: </p> <ol>
+
+<li> &AElig;lfred must be as small as possible, so that it doesn't add too
+ much to an applet's download time. </li>
+
+<li> &AElig;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.) </li>
+
+<li> &AElig;lfred must be compatible with most or all Java implementations
+ and platforms. (Write once, run anywhere.) </li>
+
+<li> &AElig;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.)</li>
+
+<li> &AElig;lfred must run as fast as possible, so that it does not slow down
+ the rest of your program. </li>
+
+<li> &AElig;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 &AElig;lfred2, correctness was a bigger concern
+ than in the original version; and a validation option is available.) </li>
+
+<li> &AElig;lfred must provide full internationalization from the first
+ release. (&AElig;lfred2 now automatically handles all encodings
+ supported by the underlying JVM; previous versions handled only
+ UTF-8, UTF_16, ASCII, and ISO-8859-1.)</li>
+
+</ol>
+
+<p>As you can see from this list, &AElig;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 <a href="http://www.xml.com/">http://www.xml.com</a>)
+</p>
+
+<p> One of the main goals of &AElig;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 &AElig;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. </p>
+
+<p> The role anticipated for this version of &AElig;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 &AElig;lfred. </p>
+
+
+<h3><a name="name">About the Name <em>&AElig;lfred</em></a></h3>
+
+<p>&AElig;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.
+&AElig;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 &AElig;lfred hopes to bring another sort of
+literacy to Java, using XML, at least, if full SGML is too difficult.</p>
+
+<p>The initial &AElig; ligature ("AE)" is also a reminder that XML is
+not limited to ASCII.</p>
+
+
+<h3><a name="encodings">Character Encodings</a></h3>
+
+<p> The &AElig;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:</p> <ul>
+
+ <li> UTF-8 ... the standard eight bit encoding, used unless
+ you provide an encoding declaration or a MIME charset tag.</li>
+
+ <li> 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. </li>
+
+ <li> ISO-8859-1 ... includes accented characters used in
+ much of western Europe (but excluding the Euro currency
+ symbol).</li>
+
+ <li> 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. </li>
+
+ <li> 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).
+ </li>
+
+ </ul>
+
+<p> If you use any encoding other than UTF-8 or UTF-16 you should
+make sure to label your data appropriately: </p>
+
+<blockquote>
+&lt;?xml version="1.0" encoding="<b>ISO-8859-15</b>"?&gt;
+</blockquote>
+
+<p> Encodings accessed through <code>java.io.InputStreamReader</code>
+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 <em>require</em> 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.
+</p>
+
+<p>Note that if you are using the Euro symbol with an fixed length
+eight bit encoding, you should probably be using the encoding label
+<em>iso-8859-15</em> or, with a Microsoft OS, <em>cp-1252</em>.
+Of course, UTF-8 and UTF-16 handle the Euro symbol directly.
+</p>
+
+
+<h3><a name="violations">Known Conformance Violations</a></h3>
+
+<p>Known conformance issues should be of negligible importance for
+most applications, and include: </p><ul>
+
+ <li> Rather than following the voluminous "Appendix B" rules about
+ what characters may appear in names (and name tokens), the Unicode
+ rules embedded in <em>java.lang.Character</em> 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.) </li>
+
+ <li> Text containing "]]&gt;" 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.) </li>
+
+ <li> 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. </li>
+
+ <li> 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.) </li>
+
+ <li> 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.) </li>
+
+</ul>
+
+<p> 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). </p>
+
+<p> 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 <a href=
+"http://xmlconf.sourceforge.net">http://xmlconf.sourceforge.net</a>
+for more information about SAX2/XML conformance testing. </p>
+
+
+<h3><a name="copyright">Copyright and distribution terms</a></h3>
+
+<p>
+The software in this package is distributed under the GNU General Public
+License (with a special exception described below).
+</p>
+
+<p>
+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:
+
+ <a href="http://www.gnu.org/software/classpath/">http://www.gnu.org/software/classpath/</a>
+</p>
+
+<pre>
+ Linking this library statically or dynamically with other modules is
+ making a combined work based on this library. Thus, the terms and
+ conditions of the GNU General Public License cover the whole
+ combination.
+
+ As a special exception, the copyright holders of this library give you
+ permission to link this library with independent modules to produce an
+ executable, regardless of the license terms of these independent
+ modules, and to copy and distribute the resulting executable under
+ terms of your choice, provided that you also meet, for each linked
+ independent module, the terms and conditions of the license of that
+ module. An independent module is a module which is not derived from
+ or based on this library. If you modify this library, you may extend
+ this exception to your version of the 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.
+</pre>
+
+<p> Some of this documentation was modified from the original
+&AElig;lfred README.txt file. All of it has been updated. </p>
+
+</p>
+
+
+<h2><a name="changes">Changes Since the last Microstar Release</a></h2>
+
+<p> 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. </p>
+
+<p> 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. </p>
+
+
+<h3><a name="sax2">SAX2 Support</a></h3>
+
+<p> The original version of &AElig;lfred did not support the
+SAX2 APIs. </p>
+
+<p> 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.</p>
+
+
+<h3><a name="validation">Validation</a></h3>
+
+<p> In the 'pipeline' package in this same software distribution is an
+<a href="../pipeline/ValidationConsumer.html">XML Validation component</a>
+using any full SAX2 event stream (including all document type declarations)
+to validate. There is now a <a href="XmlReader.html">XmlReader</a> class
+which combines that class and this enhanced &AElig;lfred parser, creating
+an optionally validating SAX2 parser. </p>
+
+<p> 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. </p>
+
+<h3><a name="smaller">You want Smaller?</a></h3>
+
+<p> You'll have noticed that the original version of &AElig;lfred
+had small size as a top goal. &AElig;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.</p>
+
+<h3><a name="bugfixes">Bugs Fixed</a></h3>
+
+<p> Bugs fixed in &AElig;lfred2 include: </p>
+
+<ol>
+ <li> Originally &AElig;lfred didn't close file descriptors, which
+ led to file descriptor leakage on programs which ran for any
+ length of time. </li>
+
+ <li> NOTATION declarations without system identifiers are
+ now handled correctly. </li>
+
+ <li> DTD events are now reported for all invocations of a
+ given parser, not just the first one. </li>
+
+ <li> More correct character handling: <ul>
+
+ <li> Rejects out-of-range characters, both in text and in
+ character references. </li>
+
+ <li> Correctly handles character references that expand to
+ surrogate pairs. </li>
+
+ <li> Correctly handles UTF-8 encodings of surrogate pairs. </li>
+
+ <li> Correctly handles Unicode 3.1 rules about illegal UTF-8
+ encodings: there is only one legal encoding per character. </li>
+
+ <li> PUBLIC identifiers are now rejected if they have illegal
+ characters. </li>
+
+ <li> 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.</li>
+
+ <li> Line ends are now normalized to newlines in all known
+ cases. </li>
+
+ </ul></li>
+
+ <li> Certain validity errors were previously treated as well
+ formedness violations. <ul>
+
+ <li> Repeated declarations of an element type are no
+ longer fatal errors. </li>
+
+ <li> Undeclared parameter entity references are no longer
+ fatal errors. </li>
+
+ </ul></li>
+
+ <li> Attribute handling is improved: <ul>
+
+ <li> Whitespace must exist between attributes. </li>
+
+ <li> Only one value for a given attribute is permitted. </li>
+
+ <li> ATTLIST declarations don't need to declare attributes. </li>
+
+ <li> Attribute values are normalized when required. </li>
+
+ <li> Tabs in attribute values are normalized to spaces. </li>
+
+ <li> Attribute values containing a literal "&lt;" are rejected. </li>
+
+ </ul></li>
+
+ <li> More correct entity handling: <ul>
+
+ <li> Whitespace must precede NDATA when declaring unparsed
+ entities.</li>
+
+ <li> Parameter entity declarations may not have NDATA annotations. </li>
+
+ <li> 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. </li>
+
+ <li> Entity expansions that include quote characters no longer
+ confuse parsing of strings using such expansions. </li>
+
+ <li> Whitespace in the values of internal entities is not mapped
+ to space characters. </li>
+
+ <li> 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. </li>
+
+ <li> Malformed general entity references in entity declarations are
+ now detected. </li>
+
+ </ul></li>
+
+ <li> Neither conditional sections
+ nor parameter entity references within markup declarations
+ are permitted in the internal subset. </li>
+
+ <li> Processing instructions whose target names are "XML"
+ (ignoring case) are now rejected. </li>
+
+ <li> Comments may not include "--".</li>
+
+ <li> Most "]]&gt;" sequences in text are rejected. </li>
+
+ <li> Correct syntax for standalone declarations is enforced. </li>
+
+ <li> Setting a locale for diagnostics only produces an exception
+ if the language of that locale isn't English. </li>
+
+ <li> 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. </li>
+
+ <li> 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.</li>
+
+ <li> 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.) </li>
+
+</ol>
+
+<p> Other bugs may also have been fixed. </p>
+
+<p> 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 &AElig;lfred2. </p>
+
+</body></html>
+
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.
+ *
+ * <p> 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.
+ *
+ * <p> 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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;
+
+
+/**
+ * <p> "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.</p>
+ *
+ * <p> 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.</p>
+ *
+ * <p> 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). </p>
+ *
+ * <p><em>You are strongly advised not to use "children" of any attribute
+ * nodes you work with.</em> </p>
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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".
+ *
+ * <p>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".
+ *
+ * <p>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.
+ * <p>
+ * 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)}.
+ * </p>
+ *
+ * @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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the attribute name (same as getNodeName)
+ */
+ public final String getName()
+ {
+ return getNodeName();
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the attribute value, with character and entity
+ * references substituted.
+ * <em>NOTE: entity refs as children aren't currently handled.</em>
+ */
+ 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();
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the value of the attribute as a non-null string; same
+ * as getNodeValue.
+ * <em>NOTE: entity refs as children aren't currently handled.</em>
+ */
+ public final String getValue()
+ {
+ return getNodeValue();
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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 <code>null</code>.
+ */
+ 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;
+
+/**
+ * <p> "CDATASection" implementation.
+ * This is a non-core DOM class, supporting the "XML" feature.
+ * CDATA sections are just ways to represent text using different
+ * delimeters. </p>
+ *
+ * <p> <em>You are strongly advised not to use CDATASection nodes.</em>
+ * The advantage of having slightly prettier ways to print text that may
+ * have lots of embedded XML delimiters, such as "&amp;" and "&lt;",
+ * can be dwarfed by the cost of dealing with multiple kinds of text
+ * nodes in all your algorithms. </p>
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class DomCDATASection
+ extends DomText
+ implements CDATASection
+{
+
+ /**
+ * Constructs a CDATA section node associated with the specified
+ * document and holding the specified data.
+ *
+ * <p>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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+
+
+/**
+ * <p> Abstract "CharacterData" implementation. This
+ * facilitates reusing code in classes implementing subtypes of that DOM
+ * interface (Text, Comment, CDATASection). </p>
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the value of this node.
+ */
+ public String getNodeValue()
+ {
+ return text;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the value of this node; same as getNodeValue.
+ */
+ public final String getData()
+ {
+ return text;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the length of the data.
+ */
+ public int getLength()
+ {
+ return text.length();
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Assigns the value of this node; same as setNodeValue.
+ */
+ final public void setData(String data)
+ {
+ setNodeValue(data);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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 <code>null</code>.
+ * @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;
+
+/**
+ * <p> "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. </p>
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class DomComment
+ extends DomCharacterData
+ implements Comment
+{
+
+ /**
+ * Constructs a comment node associated with the specified
+ * document and holding the specified data.
+ *
+ * <p>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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+
+/**
+ * <p> DOMException implementation. The version that
+ * is provided by the W3C is abstract, so it can't be instantiated.
+ *
+ * <p> 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;
+
+/**
+ * <p> "DocumentType" implementation (with no extensions for supporting
+ * any document typing information). This is a non-core DOM class,
+ * supporting the "XML" feature. </p>
+ *
+ * <p> <em>Few XML applications will actually care about this partial
+ * DTD support</em>, 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! </p>
+ *
+ * <p> 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 &lt;!DOCTYPE ...&gt; declaration. </p>
+ *
+ * <p> In short, <em>you are strongly advised not to rely on this incomplete
+ * DTD functionality</em> in your application code.</p>
+ *
+ * @see DomEntity
+ * @see DomEntityReference
+ * @see DomNotation
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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.
+ *
+ * <p>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.
+ *
+ * <p> 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();
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the root element's name (just like getNodeName).
+ */
+ final public String getName()
+ {
+ return getNodeName();
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns information about any general entities declared
+ * in the DTD.
+ *
+ * <p><em>Note: DOM L1 doesn't throw a DOMException here, but
+ * then it doesn't have the strange construction rules of L2.</em>
+ *
+ * @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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns information about any notations declared in the DTD.
+ *
+ * <p><em>Note: DOM L1 doesn't throw a DOMException here, but
+ * then it doesn't have the strange construction rules of L2.</em>
+ *
+ * @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;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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 <em>entities</em> or <em>notations</em> attributes
+ * of this Document "Type" object.
+ *
+ * <p> 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 <code>null</code>.
+ * 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);
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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;
+
+/**
+ * <p> "Document" and "DocumentTraversal" implementation.
+ *
+ * <p> 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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.
+ *
+ * <p> 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 <code>building</code> 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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the constant "#document".
+ */
+ final public String getNodeName()
+ {
+ return "#document";
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the document's DOMImplementation.
+ */
+ final public DOMImplementation getImplementation()
+ {
+ return implementation;
+ }
+
+ /**
+ * <b>DOM L1 (relocated in DOM L2)</b>
+ * Returns the element with the specified "ID" attribute, or null.
+ *
+ * <p>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);
+ }
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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);
+ }
+ }
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns a newly created document fragment.
+ */
+ public DocumentFragment createDocumentFragment()
+ {
+ return new DomDocumentFragment(this);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+ }
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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.
+ *
+ * <p> 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.
+ *
+ * <p> Note also that there is no requirement that the specified node
+ * be associated with a different document. This differs from the
+ * <em>cloneNode</em> 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;
+ }
+
+ /**
+ * <b>DOM L2 (Traversal)</b>
+ * 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 &amp; Save implementation.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 &amp; Save
+ * implementation.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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;
+
+/**
+ * <p> "DocumentFragment" implementation. </p>
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class DomDocumentFragment
+ extends DomNode
+ implements DocumentFragment
+{
+
+ /**
+ * Constructs a DocumentFragment node associated with the
+ * specified document.
+ *
+ * <p>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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+
+/**
+ * <p> "Element" implementation.
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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.
+ *
+ * <p>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);
+ }
+
+ /**
+ * <p>
+ * 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.
+ * </p>
+ * <p>
+ * 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)}.
+ * </p>
+ *
+ * @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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the element's attributes
+ */
+ public NamedNodeMap getAttributes()
+ {
+ if (attributes == null)
+ {
+ attributes = new DomNamedNodeMap(this, Node.ATTRIBUTE_NODE);
+ }
+ return attributes;
+ }
+
+ /**
+ * <b>DOM L2></b>
+ * 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();
+ }
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the element name (same as getNodeName).
+ */
+ final public String getTagName()
+ {
+ return getNodeName();
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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();
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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();
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Stores the specified attribute, optionally overwriting any
+ * existing one with that name.
+ */
+ public Attr setAttributeNode(Attr attr)
+ {
+ return (Attr) getAttributes().setNamedItem(attr);
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * Stores the specified attribute, optionally overwriting any
+ * existing one with that name.
+ */
+ public Attr setAttributeNodeNS(Attr attr)
+ {
+ return (Attr) getAttributes().setNamedItemNS(attr);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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.
+ *
+ * <p>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;
+ }
+ }
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Removes the appropriate attribute node; the name is the
+ * nodeName property of the attribute.
+ *
+ * <p>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());
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * Removes the appropriate attribute node; the name combines
+ * the namespace name and the local part.
+ *
+ * <p>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;
+
+/**
+ * <p> "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:</p><dl>
+ *
+ * <dt><em>Unparsed Entities</em></dt>
+ * <dd>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.) </dd>
+ *
+ * <dt><em>Parsed Entities</em></dt>
+ * <dd> 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. <em>This implementation
+ * currently does not permit children to be added to Entities.</em>
+ * There are related issues with the use of EntityReference nodes. </dd>
+ *
+ * </dl>
+ *
+ * <p> In short, <em>avoid using this DOM functionality</em>.
+ *
+ * @see DomDoctype
+ * @see DomEntityReference
+ * @see DomNotation
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class DomEntity
+ extends DomExtern
+ implements Entity
+{
+
+ private String notation;
+
+ /**
+ * Constructs an Entity node associated with the specified document,
+ * with the specified descriptive data.
+ *
+ * <p>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();
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+
+/**
+ * <p> "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;amp;")
+ * or character references, which are always directly expanded in
+ * DOM trees.</p>
+ *
+ * <p> 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 <em>Document.ImportNode</em> method will not have children.
+ * The level of functionality you may get is extremely variable.
+ *
+ * <p> 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.
+ *
+ * <p> In short, <em>avoid using this DOM functionality</em>.
+ *
+ * @see DomDoctype
+ * @see DomEntity
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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.
+ *
+ * <p>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.
+ *
+ * <p> Applications may define application specific event subclasses, but
+ * should otherwise use the <em>DocumentTraversal</em> 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 <em>target.dispatchEvent(event)</em> 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 <em>getTarget</em> 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.
+ *
+ * <p> <em> Avoid using this </em> 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. </p>
+ *
+ * <p> Note that this method is not final, specifically to enable
+ * enforcing of policies about events always propagating. </p>
+ */
+ 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;
+
+/**
+ * <p> 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. </p>
+ *
+ * <p> 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. </p>
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the SYSTEM identifier associated with this object, if any.
+ */
+ public final String getSystemId()
+ {
+ return systemId;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the PUBLIC identifier associated with this object, if any.
+ */
+ public final String getPublicId()
+ {
+ return publicId;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+
+/**
+ * <p> "DOMImplementation" implementation. </p>
+ *
+ * <p> 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class DomImpl
+ implements DOMImplementation, DOMImplementationLS
+{
+
+ /**
+ * Constructs a DOMImplementation object which supports
+ * "XML" and other DOM Level 2 features.
+ */
+ public DomImpl()
+ {
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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.
+ *
+ * <p> 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). <em>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 <b>(a)</b> it's known if a DocumentType
+ * object is needed, and <b>(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.</em>
+ *(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);
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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;
+
+/**
+ * <p> "NodeIterator" implementation, usable with any L2 DOM which
+ * supports MutationEvents. </p>
+ *
+ * @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);
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * Returns the flag controlling whether iteration descends
+ * through entity references.
+ */
+ public boolean getExpandEntityReferences()
+ {
+ return expandEntityReferences;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * Returns the filter provided during construction.
+ */
+ public NodeFilter getFilter()
+ {
+ return filter;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * Returns the root of the tree this is iterating through.
+ */
+ public Node getRoot()
+ {
+ return root;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * Returns the mask of flags provided during construction.
+ */
+ public int getWhatToShow()
+ {
+ return whatToShow;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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.
+ *
+ * <p> 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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;
+
+/**
+ * <p> "NamedNodeMap" implementation. </p>
+ * Used mostly to hold element attributes, but sometimes also
+ * to list notations or entities.
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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();
+ }
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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();
+ }
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+
+/**
+ * <p> "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. </p>
+ *
+ * <p> 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.</p>
+ *
+ * <p> 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. </p>
+ *
+ * <p> Note that there is a namespace-aware name comparison method,
+ * <em>nameAndTypeEquals</em>, 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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();
+ }
+
+
+ /**
+ * <b>DOM L1</b>
+ * Returns null; Element subclasses must override this method.
+ */
+ public NamedNodeMap getAttributes()
+ {
+ return null;
+ }
+
+ /**
+ * <b>DOM L2></b>
+ * Returns true iff this is an element node with attributes.
+ */
+ public boolean hasAttributes()
+ {
+ return false;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the first child of this node, or null if there are none.
+ */
+ public Node getFirstChild()
+ {
+ return first;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the last child of this node, or null if there are none.
+ */
+ public Node getLastChild()
+ {
+ return last;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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);
+ }
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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);
+ }
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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);
+ }
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Removes the specified child from this node's list of children,
+ * or else reports an exception.
+ *
+ * <p> Causes a DOMNodeRemoved mutation event to be reported.
+ *
+ * <p> 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);
+ }
+ }
+
+ /**
+ * <b>DOM L1 (NodeList)</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L1 (NodeList)</b>
+ * 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()
+ {
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the previous sibling, if one is known.
+ */
+ public Node getNextSibling()
+ {
+ return next;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the previous sibling, if one is known.
+ */
+ public Node getPreviousSibling()
+ {
+ return previous;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the parent node, if one is known.
+ */
+ public Node getParentNode()
+ {
+ return parent;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L1 (modified in L2)</b>
+ * 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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Does nothing; this must be overridden (along with the
+ * getNodeValue method) for nodes with a non-null defined value.
+ */
+ public void setNodeValue(String value)
+ {
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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();
+
+ /**
+ * <b>DOM L2</b>
+ * Does nothing; this must be overridden (along with the
+ * getPrefix method) for element and attribute nodes.
+ */
+ public void setPrefix(String prefix)
+ {
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * Returns null; this must be overridden for element and
+ * attribute nodes.
+ */
+ public String getPrefix()
+ {
+ return null;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * Returns null; this must be overridden for element and
+ * attribute nodes.
+ */
+ public String getNamespaceURI()
+ {
+ return null;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * Returns the node name; this must be overridden for element and
+ * attribute nodes.
+ */
+ public String getLocalName()
+ {
+ return null;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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.
+
+ /**
+ * <b>DOM L1</b>
+ * 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);
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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();
+ }
+ }
+
+ /**
+ * <b>DOM L2 (Events)</b>
+ * Returns an instance of the specified type of event object.
+ * Understands about DOM Mutation, HTML, and UI events.
+ *
+ * <p>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".
+ * <em>The event "name" is a different kind of "type".</em>
+ */
+ 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);
+ }
+
+ /**
+ * <b>DOM L2 (Events)</b>
+ * 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");
+ }
+
+ }
+
+ /**
+ * <b>DOM L2 (Events)</b>
+ * 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
+ }
+ }
+
+ /**
+ * <b>DOM L2 (Events)</b>
+ * 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
+ }
+
+ /**
+ * <b>DOM L1 (relocated in DOM L2)</b>
+ * 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.
+ *
+ * <p>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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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;
+
+/**
+ * <p> "Notation" implementation. This is a non-core DOM class, supporting
+ * the "XML" feature. </p>
+ *
+ * <p> 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.
+ * </p>
+ *
+ * <p> In short, <em>avoid using this DOM functionality</em>.
+ *
+ * @see DomDoctype
+ * @see DomEntity
+ * @see DomPI
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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.
+ *
+ * <p>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;
+
+/**
+ * <p> Abstract implemention of namespace support. This facilitates
+ * sharing code for attribute and element nodes.
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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();
+ }
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * Returns the node's namespace URI
+ * <em>or null</em> 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();
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * Returns any prefix part of the node's name (before any colon).
+ */
+ public final String getPrefix()
+ {
+ return prefix;
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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();
+ }
+
+ /**
+ * <b>DOM L2</b>
+ * 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;
+
+/**
+ * <p> "ProcessingInstruction" (PI) implementation.
+ * This is a non-core DOM class, supporting the "XML" feature. </p>
+ *
+ * <p> 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.</p>
+ *
+ * <p> Also of note is that PI support is part of SAX, so that XML
+ * systems using PIs can choose among multiple APIs. </p>
+ *
+ * @see DomNotation
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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.
+ *
+ * <p>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;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the target of the processing instruction.
+ */
+ public final String getTarget()
+ {
+ return target;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the target of the processing instruction
+ * (same as getTarget).
+ */
+ public final String getNodeName()
+ {
+ return target;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the data associated with the processing instruction.
+ */
+ public final String getData()
+ {
+ return data;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the data associated with the processing instruction
+ * (same as getData).
+ */
+ public final String getNodeValue()
+ {
+ return data;
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Assigns the data associated with the processing instruction;
+ * same as setNodeValue.
+ */
+ public final void setData(String data)
+ {
+ setNodeValue(data);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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;
+
+/**
+ * <p> "Text" implementation. </p>
+ *
+ * @author David Brownell
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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.
+ *
+ * <p>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);
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * Returns the string "#text".
+ */
+ // can't be 'final' with CDATA subclassing
+ public String getNodeName()
+ {
+ return "#text";
+ }
+
+ /**
+ * <b>DOM L1</b>
+ * 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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, <code>&lt;b&gt;&lt;i&gt;c&lt;/b&gt;d</code>
+ * is parsed as <code>&lt;b&gt;&lt;i&gt;c&lt;/i&gt;&lt;/b&gt;&lt;i&gt;d</code> .
+ *
+ * @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 ( &lt;! ... &gt; ).
+ * 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ * @author <a href='mailto:mark@klomp.org'>Mark Wielaard</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 @@
+<html>
+<body>
+
+<p>
+This is a Free Software DOM Level 3 implementation, supporting these features:
+<ul>
+<li>"XML"</li>
+<li>"Events"</li>
+<li>"MutationEvents"</li>
+<li>"HTMLEvents" (won't generate them though)</li>
+<li>"UIEvents" (also won't generate them)</li>
+<li>"USER-Events" (a conformant extension)</li>
+<li>"Traversal" (optional)</li>
+<li>"XPath"</li>
+<li>"LS" and "LS-Async"</li>
+</ul>
+It is intended to be a reasonable base both for
+experimentation and supporting additional DOM modules as clean layers.
+</p>
+
+<p>
+Note that while DOM does not specify its behavior in the
+face of concurrent access, this implementation does.
+Specifically:
+<ul>
+<li>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.</li>
+<li>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.</li>
+</ul>
+</p>
+
+<h3>Design Goals</h3>
+
+<p>
+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:
+</p>
+
+<ul>
+<li>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.</li>
+
+<li> Free Software. This one is distributed under the GPL (with
+"library exception") so it can be used with a different class of
+application.</li>
+
+<li>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.</li>
+
+<li>Sanity check the then-current Last Call DOM draft. Best to find
+bugs early, when they're relatively fixable. Yes, bugs were found.</li>
+
+<li>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.</li>
+
+<li>OK, I'm a hacker, I like to write code.</li>
+</ul>
+
+<p>
+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). </p>
+
+
+<h3>Open Issues</h3>
+
+<p>At this writing:</p>
+<ul>
+<li>See below for some restrictions on the mutation event
+support ... some events aren't reported (and likely won't be).</li>
+
+<li>More testing and conformance work is needed.</li>
+
+<li>We need an XML Schema validator (actually we need validation in the DOM
+full stop).</li>
+</ul>
+
+<p>
+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).
+</p>
+
+
+<h2><a name="features">Features of this Package</a></h2>
+
+<p> 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. </p>
+
+<h3> Core Feature Set: "XML" </h3>
+
+<p> 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: </p> <ol>
+
+ <li> 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.</li>
+
+ <li> 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. </li>
+
+ <li> 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. </li>
+
+ <li> 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.</li>
+
+ </ol>
+
+<h3> Optional Feature Sets: "Events", and friends </h3>
+
+<p> 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! </p>
+
+<p> Three mutation events aren't currently generated:</p> <ul>
+
+ <li> <em>DOMSubtreeModified</em> 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. </li>
+
+ <li> <em>DOMNodeRemovedFromDocument</em> and
+ <em>DOMNodeInsertedIntoDocument</em> are supposed to get sent to
+ every node in a subtree that gets removed or inserted (respectively).
+ This can be <em>extremely costly</em>, 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.</li>
+
+ </ul>
+
+<p> 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. </p>
+
+<p> Also, note that it is a <em>Bad Thing&#153;</em> 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? </p>
+
+<p> 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.</p>
+
+<p> 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. </p>
+
+<p><em>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.</em>
+
+
+<h3> Optional Feature: "Traversal" </h3>
+
+<p> 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. </p>
+
+<p> 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. </p>
+
+<p> At this writing, the "TreeWalker" interface isn't implemented. </p>
+
+
+
+<h2><a name='avoid'>DOM Functionality to Avoid</a></h2>
+
+<p> For what appear to be a combination of historical and "committee
+logic" reasons, DOM has a number of <em>features which I strongly advise
+you to avoid using</em> in your library and application code. These
+include the following types of DOM nodes; see the documentation for the
+implementation class for more information: <ul>
+
+ <li> CDATASection
+ (<a href='DomCDATA.html'>DomCDATA</a> class)
+ ... use normal Text nodes instead, so you don't have to make
+ every algorithm recognize multiple types of character data
+
+ <li> DocumentType
+ (<a href='DomDoctype.html'>DomDocType</a> class)
+ ... if this held actual typing information, it might be useful
+
+ <li> Entity
+ (<a href='DomEntity.html'>DomEntity</a> class)
+ ... neither parsed nor unparsed entities work well in DOM; it
+ won't even tell you which attributes identify unparsed entities
+
+ <li> EntityReference
+ (<a href='DomEntityReference.html'>DomEntityReference</a> class)
+ ... permitted implementation variances are extreme, all children
+ are readonly, and these can interact poorly with namespaces
+
+ <li> Notation
+ (<a href='DomNotation.html'>DomNotation</a> 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
+
+ </ul>
+
+<p> 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).</p>
+
+<p> 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 <a href='DomAttr.html'>DomAttr</a>
+documentation for more information.) </p>
+
+<p> 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. </p>
+
+<p> (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.) </p>
+
+</body>
+</html>
+
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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>libxslt</code>.
+ *
+ * @author Julian Scheid
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>TransformerFactory</code> producing
+ * <code>Transformer</code> objects which use <code>libxslt</code>
+ * for transformation.
+ *
+ * @author Julian Scheid
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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
+ * <code>null</code> 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 @@
+<body>
+<p>
+ 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.
+</p>
+
+<p>
+ <b>Usage:</b>
+ <li>Set the system property <code>javax.xml.transform.TransformerFactory</code>
+ to <code>gnu.xml.libxmlj.GnomeTransformerFactory</code>.</li>
+ </ul>
+</p>
+</body>
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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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.
+ *
+ * <p>In effect, this makes a remote procedure call to the URI, with the
+ * request and response document syntax as chosen by the application.
+ * <em>Note that all the input events must be seen, and sent to the URI,
+ * before the first output event can be seen. </em> 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.
+ *
+ * <p> 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.)
+ *
+ * <p> <em>Be strict in what you send, liberal in what you accept,</em> 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.
+ *
+ * <p>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).
+ *
+ * <p> 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. <em>Before you convert a DOM to an output document,
+ * you should plan to postprocess it to create or repair such namespace
+ * information.</em> The {@link NSFilter} pipeline stage does such work.
+ *
+ * <p> <em>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. </em>
+ *
+ * @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.
+ *
+ * <p> This event consumer acts as a buffer and filter, in that it
+ * builds a DOM tree and then writes it out when <em>endDocument</em>
+ * 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 <em>endDocument</em> 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.
+ *
+ * <p> 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). </p>
+ */
+ 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.
+ *
+ * <p> Two important categories of consumers include <em>filters</em>, which
+ * process events and pass them on to other consumers, and <em>terminus</em>
+ * (or <em>terminal</em>) 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.
+ *
+ * <p> 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: <ul>
+ *
+ * <li> To serve as a passthrough, sending all events to a second consumer.
+ * The second consumer may be identified through {@link #getNext}.
+ *
+ * <li> To serve as a dead end, with all handlers null;
+ * {@link #getNext} returns null.
+ *
+ * </ul>
+ *
+ * <p> 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}.
+ *
+ * <p> 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 <em>setContentHandler(this)</em>,
+ * 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.
+ *
+ * <p> 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.
+ *
+ * <hr />
+ *
+ * <p> This may be viewed as the consumer oriented analogue of the SAX2
+ * {@link org.xml.sax.helpers.XMLFilterImpl XMLFilterImpl} class.
+ * Key differences include: <ul>
+ *
+ * <li> This fully separates consumer and producer roles: it
+ * does not implement the producer side <em>XMLReader</em> or
+ * <em>EntityResolver</em> interfaces, so it can only be used
+ * in "push" mode (it has no <em>parse()</em> methods).
+ *
+ * <li> "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.
+ *
+ * <li> 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.)
+ *
+ * <li> 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.
+ *
+ * <li> 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.
+ *
+ * </ul>
+ *
+ * <p> 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.
+ *
+ * <hr />
+ *
+ * <p> 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.
+ *
+ * <p> 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}. <ul>
+ *
+ * <li> {@link NSFilter} will be removed if the producer can be
+ * told not to discard namespace data, using the "namespace-prefixes"
+ * feature flag.
+ *
+ * <li> {@link ValidationConsumer} will be removed if the producer
+ * can be told to validate, using the "validation" feature flag.
+ *
+ * <li> {@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.
+ *
+ * <li> {@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.
+ *
+ * <li> 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.
+ *
+ * </ul>
+ *
+ * <p> 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.
+ *
+ * <p> <em>Upstream Event Setup:</em>
+ * 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.
+ *
+ * <p> <em>Downstream Event Setup:</em>
+ * 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
+
+ /** <b>SAX2:</b> passes this callback to the next consumer, if any */
+ public void setDocumentLocator (Locator locator)
+ {
+ this.locator = locator;
+ if (docNext != null)
+ docNext.setDocumentLocator (locator);
+ }
+
+ /** <b>SAX2:</b> passes this callback to the next consumer, if any */
+ public void startDocument () throws SAXException
+ {
+ if (docNext != null)
+ docNext.startDocument ();
+ }
+
+ /** <b>SAX2:</b> passes this callback to the next consumer, if any */
+ public void skippedEntity (String name) throws SAXException
+ {
+ if (docNext != null)
+ docNext.skippedEntity (name);
+ }
+
+ /** <b>SAX2:</b> 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);
+ }
+
+ /** <b>SAX2:</b> 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);
+ }
+
+ /** <b>SAX2:</b> 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);
+ }
+
+ /** <b>SAX2:</b> 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);
+ }
+
+ /** <b>SAX2:</b> 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);
+ }
+
+ /** <b>SAX2:</b> 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);
+ }
+
+ /** <b>SAX2:</b> passes this callback to the next consumer, if any */
+ public void endPrefixMapping (String prefix) throws SAXException
+ {
+ if (docNext != null)
+ docNext.endPrefixMapping (prefix);
+ }
+
+ /** <b>SAX2:</b> passes this callback to the next consumer, if any */
+ public void endDocument () throws SAXException
+ {
+ if (docNext != null)
+ docNext.endDocument ();
+ locator = null;
+ }
+
+
+ // DTD HANDLER DELEGATIONS
+
+ /** <b>SAX1:</b> 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);
+ }
+
+ /** <b>SAX1:</b> 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
+
+ /** <b>SAX2:</b> 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);
+ }
+
+ /** <b>SAX2:</b> passes this callback to the next consumer, if any */
+ public void endDTD ()
+ throws SAXException
+ {
+ if (lexNext != null)
+ lexNext.endDTD ();
+ }
+
+ /** <b>SAX2:</b> 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);
+ }
+
+ /** <b>SAX2:</b> passes this callback to the next consumer, if any */
+ public void startCDATA ()
+ throws SAXException
+ {
+ if (lexNext != null)
+ lexNext.startCDATA ();
+ }
+
+ /** <b>SAX2:</b> passes this callback to the next consumer, if any */
+ public void endCDATA ()
+ throws SAXException
+ {
+ if (lexNext != null)
+ lexNext.endCDATA ();
+ }
+
+ /**
+ * <b>SAX2:</b> passes this callback to the next consumer, if any.
+ */
+ public void startEntity (String name)
+ throws SAXException
+ {
+ if (lexNext != null)
+ lexNext.startEntity (name);
+ }
+
+ /**
+ * <b>SAX2:</b> 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
+
+
+ /** <b>SAX2:</b> 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);
+ }
+
+ /** <b>SAX2:</b> 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);
+ }
+
+ /** <b>SAX2:</b> 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);
+ }
+
+ /** <b>SAX2:</b> 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.
+ *
+ * <p> 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.
+ *
+ * <p><em>FIXME:</em> 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: <ul>
+ *
+ * <li> 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 <em>namespace-prefixes</em> value from the default
+ * to <em>true</em>, effectively eliminating the need to use this
+ * filter on their output.)
+ *
+ * <li> 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.
+ *
+ * <li> 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.
+ *
+ * </ul>
+ *
+ * <p> 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.
+ *
+ * <p> 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: <pre>
+ * nsfix | validate | write ( stdout )</pre>
+ *
+ * <p> 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.
+ *
+ * <p> 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:</p>
+
+ <table border="1" cellpadding="3" cellspacing="0">
+ <tr bgcolor="#ccccff" class="TableHeadingColor">
+ <th align="center" width="5%">Stage</th>
+ <th align="center" width="9%">Parameter</th>
+ <th align="center" width="1%">Terminus</th>
+ <th align="center">Description</th>
+ </tr>
+
+ <tr valign="top" align="center">
+ <td><a href="../dom/Consumer.html">dom</a></td>
+ <td><em>none</em></td>
+ <td> yes </td>
+ <td align="left"> Applications code can access a DOM Document built
+ from the input event stream. When used as a filter, this buffers
+ data up to an <em>endDocument</em> 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). </td>
+ </tr>
+ <tr valign="top" align="center">
+ <td><a href="NSFilter.html">nsfix</a></td>
+ <td><em>none</em></td>
+ <td>no</td>
+ <td align="left">This 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. </td>
+ </tr>
+ <tr valign="top" align="center">
+ <td><a href="EventFilter.html">null</a></td>
+ <td><em>none</em></td>
+ <td>yes</td>
+ <td align="left">This stage ignores all input event data.</td>
+ </tr>
+ <tr valign="top" align="center">
+ <td><a href="CallFilter.html">server</a></td>
+ <td><em>required</em><br> server URL </td>
+ <td>no</td>
+ <td align="left">Sends 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.</td>
+ </tr>
+ <tr valign="top" align="center">
+ <td><a href="TeeConsumer.html">tee</a></td>
+ <td><em>required</em><br> first pipeline</td>
+ <td>no</td>
+ <td align="left">This 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.</td>
+ </tr>
+
+ <tr valign="top" align="center">
+ <td><a href="ValidationConsumer.html">validate</a></td>
+ <td><em>none</em></td>
+ <td>yes</td>
+ <td align="left">This checks for validity errors, and reports them
+ through its error handler. The input must include declaration events
+ and some lexical events. </td>
+ </tr>
+ <tr valign="top" align="center">
+ <td><a href="WellFormednessFilter.html">wf</a></td>
+ <td><em>none</em></td>
+ <td>yes</td>
+ <td align="left"> 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.</td>
+ </tr>
+ <tr valign="top" align="center">
+ <td>write</td>
+ <td><em>required</em><br> "stdout", "stderr", or filename</td>
+ <td>yes</td>
+ <td align="left"> 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
+ <em>System.out</em> and <em>System.err</em> respectively; names must
+ correspond to files which don't yet exist.</td>
+ </tr>
+ <tr valign="top" align="center">
+ <td>xhtml</td>
+ <td><em>required</em><br> "stdout", "stderr", or filename</td>
+ <td>yes</td>
+ <td align="left"> Like <em>write</em> (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.</td>
+ </tr>
+ <tr valign="top" align="center">
+ <td><a href="XIncludeFilter.html">xinclude</a></td>
+ <td><em>none</em></td>
+ <td>no</td>
+ <td align="left">This 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.
+ </td>
+ </tr>
+ <tr valign="top" align="center">
+ <td><a href="XsltFilter.html">xslt</a></td>
+ <td><em>required</em><br> XSLT stylesheet URI</td>
+ <td>no</td>
+ <td align="left">This 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.
+ </td>
+ </tr>
+
+ </table>
+
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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.
+ *
+ * <p> 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);
+ }
+
+ /** <b>EventConsumer</b> Returns the document handler being used. */
+ public ContentHandler getContentHandler ()
+ { return this; }
+
+ /** <b>EventConsumer</b> Returns the dtd handler being used. */
+ public DTDHandler getDTDHandler ()
+ { return this; }
+
+ /** <b>XMLReader</b>Retrieves 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: </p> <ol>
+ *
+ * <li> Conform to the specification of a non-validating XML parser that
+ * reads all external entities, reported using SAX2 events. </li>
+ *
+ * <li> Report ignorable whitespace as such (through the ContentHandler
+ * interface). This is, strictly speaking, optional for nonvalidating
+ * XML processors. </li>
+ *
+ * <li> Make SAX2 DeclHandler callbacks, with default
+ * attribute values already normalized (and without "&lt;").</li>
+ *
+ * <li> Make SAX2 LexicalHandler startDTD() and endDTD ()
+ * callbacks. </li>
+ *
+ * <li> Act as if the <em>(URI)/namespace-prefixes</em> property were
+ * set to true, by providing XML 1.0 names and all <code>xmlns*</code>
+ * attributes (rather than omitting either or both). </li>
+ *
+ * </ol>
+ *
+ * <p> At this writing, the major SAX2 parsers (such as &AElig;lfred2,
+ * Crimson, and Xerces) meet these requirements, and this validation
+ * module is used by the optional &AElig;lfred2 validation support.
+ * </p>
+ *
+ * <p> 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, <em>because of layering it doesn't need a parser</em> 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.</p>
+ *
+ * <p> 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 <em>characters</em> event
+ * callback, rather than the first non-whitespace character. </p>
+ *
+ * <hr />
+ *
+ * <!--
+ * <p> Of interest is the fact that unlike most currently known XML validators,
+ * this one can report some cases of non-determinism in element content models.
+ * It is a compile-time option, enabled by default. This will only report
+ * such XML errors if they relate to content actually appearing in a document;
+ * content models aren't aggressively scanned for non-deterministic structure.
+ * Documents which trigger such non-deterministic transitions may be handled
+ * differently by different validating parsers, without losing conformance
+ * to the XML specification. </p>
+ * -->
+ *
+ * <p> Current limitations of the validation performed are in roughly three
+ * categories. </p>
+ *
+ * <p> The first category represents constraints which demand violations
+ * of software layering: exposing lexical details, one of the first things
+ * that <em>application</em> 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): </p><ul>
+ *
+ * <li> The <em>Proper Declaration/PE Nesting</em> and
+ * <em>Proper Group/PE Nesting</em> 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.
+ *
+ * <li> The <em>Standalone Document Declaration</em> 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.)
+ *
+ * <li> The <em>Entity Declared</em> 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.)
+ *
+ * </ul>
+ *
+ * <p> The second category of limitations on this validation represent
+ * constraints associated with information that is not guaranteed to be
+ * available (or in one case, <em>is guaranteed not to be available</em>,
+ * through the SAX2 API: </p><ul>
+ *
+ * <li> The <em>Unique Element Type Declaration</em> VC may not be
+ * reportable, if the underlying parser happens not to expose
+ * multiple declarations. (&AElig;lfred2 reports these validity
+ * errors directly.)</li>
+ *
+ * <li> Similarly, the <em>Unique Notation Name</em> VC, added in the
+ * 14-January-2000 XML spec errata to restrict typing models used by
+ * elements, may not be reportable. (&AElig;lfred reports these
+ * validity errors directly.) </li>
+ *
+ * </ul>
+ *
+ * <p> 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.
+ * </p>
+ *
+ * <p> 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.
+ *
+ * <p> 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 ("<!DOCTYPE ");
+ writer.write (rootName);
+ if (systemId != null) {
+ writer.write ("\n ");
+ if (publicId != null) {
+ writer.write ("PUBLIC '");
+ writer.write (publicId);
+ writer.write ("'\n\t'");
+ } else
+ writer.write ("SYSTEM '");
+ writer.write (systemId);
+ writer.write ("'");
+ }
+ writer.write (" [ ");
+ if (rootName == fakeRootName) {
+ writer.write ("\n<!ELEMENT ");
+ writer.write (rootName);
+ writer.write (" EMPTY>");
+ }
+ 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;
+ }
+
+ /**
+ * <b>LexicalHandler</b> 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);
+ }
+
+ /**
+ * <b>LexicalHandler</b> 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"
+ };
+
+
+ /**
+ * <b>DecllHandler</b> 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);
+ }
+
+ /**
+ * <b>DecllHandler</b> 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);
+ }
+
+ /**
+ * <b>DecllHandler</b> 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);
+ }
+
+ /**
+ * <b>DecllHandler</b> 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);
+ }
+
+
+ /**
+ * <b>DTDHandler</b> 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);
+ }
+
+ /**
+ * <b>DTDHandler</b> 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);
+ }
+
+
+ /**
+ * <b>ContentHandler</b> 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');
+ }
+
+
+ /**
+ * <b>ContentHandler</b> 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;
+ }
+
+ /**
+ * <b>ContentHandler</b> 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);
+ }
+
+ /**
+ * <b>ContentHandler</b> 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);
+ }
+
+
+ /**
+ * <b>ContentHandler</b> 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);
+ }
+
+ /**
+ * <b>ContentHandler</b> 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.
+ *
+ * <p>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.
+ *
+ * <p>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.)
+ *
+ * <p><b>FIXME</b> 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: <ul>
+ *
+ * <li>setDocumentLocator ... may be called only before startDocument
+ *
+ * <li>startDocument/endDocument ... must be paired, and all other
+ * calls (except setDocumentLocator) must be nested within these.
+ *
+ * <li>startElement/endElement ... must be correctly paired, and
+ * may never appear within CDATA sections.
+ *
+ * <li>comment ... can't contain "--"
+ *
+ * <li>character data ... can't contain "]]&gt;"
+ *
+ * <li>whitespace ... can't contain CR
+ *
+ * <li>whitespace and character data must be within an element
+ *
+ * <li>processing instruction ... can't contain "?&gt;" or CR
+ *
+ * <li>startCDATA/endCDATA ... must be correctly paired.
+ *
+ * </ul>
+ *
+ * <p> 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 "&lt;" 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 + " ...>...</" + qName + ">");
+ // XXX could record/test namespace info
+ } catch (EmptyStackException e) {
+ fatalError ("endElement without startElement: </" + qName + ">");
+ }
+ 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
+ * <a href="http://www.w3.org/TR/xinclude">XInclude</a>, supporting its
+ * use as a kind of replacement for parsed general entities.
+ * XInclude works much like the <code>#include</code> 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:
+ *
+ * <ul>
+ *
+ * <li> URIs must not include fragment identifiers.
+ * The CR specifies support for XPointer <em>element()</em> fragment IDs,
+ * which is not currently implemented here.
+ *
+ * <li> <em>xi:fallback</em> handling of resource errors is not
+ * currently supported.
+ *
+ * <li> 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.
+ *
+ * <li> <em>xml:base</em> fixup isn't done.
+ *
+ * </ul>
+ *
+ * <p> 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()}. <em>You are strongly advised to do this.</em>
+ *
+ * <p> 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".
+ *
+ * <p>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
+ * <em>namespace-prefixes</em> flag.
+ */
+ public void setSavingPrefixes (boolean flag)
+ { savingPrefixes = flag; }
+
+ /**
+ * Returns the flag controlling the setting of the SAX2
+ * <em>namespace-prefixes</em> 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
+ }
+
+ // <xi:include parse='xml' ...>
+ // 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;
+ }
+ }
+
+ // <xi:include parse='text' ...>
+ // 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
+ * <a href="http://saxon.sourceforge.net">SAXON</a> and
+ * <a href="http://xml.apache.org/xalan-j">Xalan</a> 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 @@
+<html><head><title>
+blah
+<!--
+/*
+ * Copyright (C) 1999-2001 The Free Software Foundation, Inc.
+ */
+-->
+</title></head><body>
+
+<p>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.
+
+<p> There is a <a href="PipelineFactory.html">PipelineFactory</a> 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
+<a href="../util/DoParse.html">DoParse</a> 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.
+
+<p> 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 <em>InputSource</em> or in
+response to XML messages sent from clients using <em>CallFilter</em>
+pipeline stages. Such facilities are available using the simple syntax
+for pipeline construction.
+
+
+<h2> Programming Models </h2>
+
+<p> Pipelines should be simple to understand.
+
+<ul>
+ <li> XML content, typically entire documents,
+ is pushed through consumers by producers.
+
+ <li> Pipelines are basically about consuming SAX2 callback events,
+ where the events encapsulate XML infoset-level data.<ul>
+
+ <li> Pipelines are constructed by taking one or more consumer
+ stages and combining them to produce a composite consumer.
+
+ <li> 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.
+
+ <li> Pipelines may have multiple output stages ("fan-out")
+ or multiple input stages ("fan-in") when appropriate.
+
+ <li> Pipelines may be long-lived, but need not be.
+
+ </ul>
+
+ <li> There is flexibility about event production. <ul>
+
+ <li> 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.
+
+ <li> 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.
+
+ </ul>
+
+ <li> Multiple producer threads may concurrently access a pipeline,
+ if they coordinate appropriately.
+
+ <li> Pipeline processing is not the only framework applications
+ will use.
+
+ </ul>
+
+
+<h3> Producers: XMLReader or Custom </h3>
+
+<p> 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
+<code>org.xml.sax.helpers.XMLReaderFactory</code>) or a DOM tree
+(using a <code><a href="../util/DomParser.html">DomParser</a></code>)
+These may be bound to event consumer using a convenience routine,
+<em><a href="EventFilter.html">EventFilter</a>.bind()</em>.
+Once bound, these producers may be given additional documents to
+sent through its pipeline.
+
+<p> 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.
+
+<p> SAX2 introduced an "XMLFilter" interface, which is a kind of XMLReader.
+It is most useful in conjunction with its XMLFilterImpl helper class;
+see the <em><a href="EventFilter.html">EventFilter</a></em> 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
+<a href="#fitting">pipe fitting</a> below.
+
+
+<h3> Consume to Standard or Custom Data Representations </h3>
+
+<p> Many consumers will be used to create standard representations of XML
+data. The <a href="TextConsumer.html">TextConsumer</a> takes its events
+and writes them as text for a single XML document,
+using an internal <a href="../util/XMLWriter.html">XMLWriter</a>.
+The <a href="DomConsumer.html">DomConsumer</a> takes its events and uses
+them to create and populate a DOM Document.
+
+<p> 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).
+
+
+<h3><a name="fitting">Pipe Fitting</a></h3>
+
+<p> Pipelines are composite event consumers, with each stage having
+the opportunity to transform the data before delivering it to any
+subsequent stages.
+
+<p> The <a href="PipelineFactory.html">PipelineFactory</a> 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.
+
+<p> Four basic types of pipe fitting are directly supported. These may
+be used to construct complex pipeline networks. <ul>
+
+ <li> <a href="TeeConsumer.html">TeeConsumer</a> 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.
+
+ <li> Clients can call remote components through HTTP or HTTPS using
+ the <a href="CallFilter.html">CallFilter</a> component, and Servlets
+ can implement such components by extending the
+ <a href="XmlServlet.html">XmlServlet</a> component. Java is not
+ required on either end, and transport protocols other than HTTP may
+ also be used.
+
+ <li> <a href="EventFilter.html">EventFilter</a> 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.
+
+ <li> 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.
+
+ </ul>
+
+<p> Note that filters can be as complex as
+<a href="XsltFilter.html">XSLT transforms</a>
+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.
+
+
+<h3> Coding Conventions: Filter and Terminus Stages</h3>
+
+<p> 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: <ul>
+
+ <li> 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.
+
+ <li> 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.
+
+ <li> Terminus stages may have a public constructor taking a single
+ paramter: the string value of that parameter.
+
+ <li> Terminus stages may have a public no-parameters constructor.
+
+ </ul>
+
+<p> 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.
+
+
+<h2> Debugging Tip: "Tee" Joints can Snapshot Data</h2>
+
+<p> 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.
+
+<p> If you're using pipeline descriptors so that they're easily
+administered, just stick a <em>write&nbsp;(&nbsp;filename&nbsp;)</em>
+filter into the pipeline at an appropriate point.
+
+<p> 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.
+
+<p> 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.
+
+<h2> Debugging Tip: Non-XML Producers</h2>
+
+<p> Producers in pipelines don't need to start from XML
+data structures, such as text in XML syntax (likely coming
+from some <em>XMLReader</em> that parses XML) or a
+DOM representation (perhaps with a
+<a href="../util/DomParser.html">DomParser</a>).
+
+<p> One common type of event producer will instead make
+direct calls to SAX event handlers returned from an
+<a href="EventConsumer.html">EventConsumer</a>.
+For example, making <em>ContentHandler.startElement</em>
+calls and matching <em>ContentHandler.endElement</em> calls.
+
+<p> Applications making such calls can catch certain
+common "syntax errors" by using a
+<a href="WellFormednessFilter.html">WellFormednessFilter</a>.
+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.
+
+<p> You can also arrange to validate data on the fly.
+For DTD validation, you can configure a
+<a href="ValidationConsumer.html">ValidationConsumer</a>
+to work as a filter, using any DTD you choose.
+Other validation schemes can be handled with other
+validation filters.
+
+</body></html>
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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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("<![CDATA[");
+ writer.write(data);
+ 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 <a href'mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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("<!--");
+ writer.write(encode(text, false));
+ 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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("<!DOCTYPE ");
+ writer.write(body);
+ 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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("</");
+ String prefix = name.getPrefix();
+ if (prefix != null && !"".equals(prefix))
+ {
+ writer.write(prefix);
+ writer.write(':');
+ }
+ writer.write(name.getLocalPart());
+ 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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("<!ENTITY ");
+ writer.write(name);
+ writer.write(' ');
+ if (systemId != null)
+ {
+ if (publicId != null)
+ {
+ writer.write(" PUBLIC ");
+ writer.write('"');
+ writer.write(publicId);
+ writer.write('"');
+ writer.write(' ');
+ writer.write('"');
+ writer.write(systemId);
+ writer.write('"');
+ }
+ else
+ {
+ writer.write(" SYSTEM ");
+ writer.write('"');
+ writer.write(systemId);
+ writer.write('"');
+ }
+ if (notationName != null)
+ {
+ writer.write(" NDATA ");
+ writer.write(notationName);
+ }
+ }
+ else
+ {
+ writer.write('"');
+ if (replacementText != null)
+ writer.write(replacementText);
+ writer.write('"');
+ }
+ 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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("<!NOTATION ");
+ writer.write(name);
+ if (publicId != null)
+ {
+ writer.write(" PUBLIC ");
+ writer.write('"');
+ writer.write(publicId);
+ writer.write('"');
+ writer.write(' ');
+ writer.write('"');
+ writer.write(systemId);
+ writer.write('"');
+ }
+ else
+ {
+ writer.write(" SYSTEM ");
+ writer.write('"');
+ writer.write(systemId);
+ writer.write('"');
+ }
+ 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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("<?");
+ writer.write(target);
+ if (data != null)
+ {
+ writer.write(' ');
+ writer.write(data);
+ }
+ 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:
+ * <table>
+ * <tr><th colspan='4'>Features</th></tr>
+ * <tr><td>http://gnu.org/sax/features/xml-base</td>
+ * <td colspan='2'>read/write</td>
+ * <td>Indicates or sets whether XML Base processing is enabled</td></tr>
+ * <tr><th colspan='4'>Properties</th></tr>
+ * <tr><td>http://gnu.org/sax/properties/base-uri</td>
+ * <td>read-only</td><td>String</td>
+ * <td>Returns the base URI of the current event</td></tr>
+ * <tr><td>http://gnu.org/sax/properties/document-xml-encoding</td>
+ * <td>read-only</td><td>String</td>
+ * <td>Returns the encoding specified in the XML declaration</td></tr>
+ * </table>
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <class>] <file> [<file2> [...]]");
+ 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 <class>: 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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("<?xml version='");
+ writer.write(xmlVersion);
+ writer.write('\'');
+ if (standaloneDeclared)
+ {
+ writer.write(" standalone='");
+ writer.write(xmlStandalone ? "yes" : "no");
+ writer.write('\'');
+ }
+ if (encodingDeclared)
+ {
+ writer.write(" encoding='");
+ writer.write(encoding);
+ writer.write('\'');
+ }
+ 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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("&lt;");
+ }
+ else if (c == '>')
+ {
+ if (buf == null)
+ {
+ buf = new CPStringBuilder(text.substring(0, i));
+ }
+ buf.append("&gt;");
+ }
+ else if (c == '&')
+ {
+ if (buf == null)
+ {
+ buf = new CPStringBuilder(text.substring(0, i));
+ }
+ buf.append("&amp;");
+ }
+ else if (c == '\'' && inAttr)
+ {
+ if (buf == null)
+ {
+ buf = new CPStringBuilder(text.substring(0, i));
+ }
+ buf.append("&apos;");
+ }
+ else if (c == '"' && inAttr)
+ {
+ if (buf == null)
+ {
+ buf = new CPStringBuilder(text.substring(0, i));
+ }
+ buf.append("&quot;");
+ }
+ 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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:
+ * <table>
+ * <tr><td>gnu.xml.stream.stringInterning</td>
+ * <td>Boolean</td>
+ * <td>Indicates whether markup strings will be interned</td></tr>
+ * <tr><td>gnu.xml.stream.xmlBase</td>
+ * <td>Boolean</td>
+ * <td>Indicates whether XML Base processing will be performed</td></tr>
+ * <tr><td>gnu.xml.stream.baseURI</td>
+ * <td>String</td>
+ * <td>Returns the base URI of the current event</td></tr>
+ * </table>
+ *
+ * @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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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_COMMENT = "<!--";
+ private static final String TEST_PI = "<?";
+ private static final String TEST_CDATA = "<![CDATA[";
+ private static final String TEST_XML_DECL = "<?xml";
+ private static final String TEST_DOCTYPE_DECL = "<!DOCTYPE";
+ private static final String TEST_ELEMENT_DECL = "<!ELEMENT";
+ private static final String TEST_ATTLIST_DECL = "<!ATTLIST";
+ private static final String TEST_ENTITY_DECL = "<!ENTITY";
+ private static final String TEST_NOTATION_DECL = "<!NOTATION";
+ private static final String TEST_KET = ">";
+ 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("<!["))
+ {
+ // conditional section
+ expandPE = saved;
+ if (inputStack.size() < 2)
+ error("conditional sections illegal in internal subset");
+ skipWhitespace();
+ if (tryRead("INCLUDE"))
+ {
+ skipWhitespace();
+ require('[');
+ skipWhitespace();
+ while (!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] <file> [<file2> [...]]");
+ 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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("<!--");
+ 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("-->");
+ }
+ 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("<![CDATA[");
+ writer.write(data);
+ 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("<!DOCTYPE ");
+ writer.write(dtd);
+ 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("<?xml version=\"");
+ writer.write(version);
+ writer.write("\" encoding=\"");
+ writer.write(encoding);
+ 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("&lt;");
+ else if (c == '>')
+ writer.write("&gt;");
+ else
+ writer.write("&amp;");
+ start = i + 1;
+ len = 0;
+ }
+ else if (inAttr && (c == '"' || c == '\''))
+ {
+ writer.write(chars, start, len);
+ if (c == '"')
+ writer.write("&quot;");
+ else
+ writer.write("&apos;");
+ 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("&lt;");
+ break;
+ case 0x3e: // '>'
+ writer.write("&gt;");
+ break;
+ case 0x26: // '&'
+ writer.write("&amp;");
+ break;
+ case 0x22: // '"'
+ if (inAttr)
+ writer.write("&quot;");
+ else
+ writer.write(c);
+ break;
+ case 0x27: // '\''
+ if (inAttr)
+ writer.write("&apos;");
+ 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 <code>number</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>apply-imports</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>apply-templates</code>
+ * instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>attribute</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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<Map<QName,Object>> variables;
+
+ /**
+ * Parameter value stack.
+ */
+ final LinkedList<Map<QName,Object>> parameters;
+
+ /**
+ * Argument (with-param) value stack.
+ */
+ final LinkedList<Map<QName,Object>> withParameters;
+
+ /**
+ * Only search globals.
+ */
+ boolean global;
+
+ Bindings(Stylesheet stylesheet)
+ {
+ this.stylesheet = stylesheet;
+ variables = new LinkedList<Map<QName,Object>>();
+ parameters = new LinkedList<Map<QName,Object>>();
+ withParameters = new LinkedList<Map<QName,Object>>();
+ 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<QName,Object>());
+ break;
+ case PARAM:
+ parameters.addFirst(new HashMap<QName,Object>());
+ break;
+ case WITH_PARAM:
+ withParameters.addFirst(new HashMap<QName,Object>());
+ 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<QName,Object> ctx1 = variables.getLast();
+ Map<QName,Object> ctx2 = parameters.getLast();
+ return (ctx1.containsKey(name) || ctx2.containsKey(name));
+ }
+ Iterator<Map<QName,Object>> i = null;
+ switch (type)
+ {
+ case VARIABLE:
+ i = variables.iterator();
+ break;
+ case PARAM:
+ i = parameters.iterator();
+ break;
+ case WITH_PARAM:
+ Map<QName,Object> ctx = withParameters.getFirst();
+ return ctx.containsKey(name);
+ }
+ if (i != null)
+ {
+ while (i.hasNext())
+ {
+ Map<QName,Object> 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<QName,Object> 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<QName,Object> cwp = withParameters.getFirst();
+ ret = cwp.get(name);
+ //System.err.println("\twith-param: ret="+ret);
+ }
+ if (ret == null)
+ {
+ for (Iterator<Map<QName,Object>> i = variables.iterator();
+ i.hasNext() && ret == null; )
+ {
+ Map<QName,Object> vctx = i.next();
+ ret = vctx.get(name);
+ }
+ //System.err.println("\tvariable: ret="+ret);
+ }
+ if (ret == null)
+ {
+ for (Iterator<Map<QName,Object>> i = parameters.iterator();
+ i.hasNext() && ret == null; )
+ {
+ Map<QName,Object> 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<QName,Object> vctx = variables.getFirst();
+ vctx.put(name, value);
+ break;
+ case PARAM:
+ Map<QName,Object> pctx = parameters.getFirst();
+ pctx.put(name, value);
+ break;
+ case WITH_PARAM:
+ Map<QName,Object> 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<QName> seen = new HashSet<QName>();
+ Map<QName,Object> wctx = withParameters.getFirst();
+ buf.append('(');
+ for (Map.Entry<QName,Object> 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<QName,Object> ctx : variables)
+ {
+ for (Map.Entry<QName,Object> 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<QName,Object> ctx : parameters)
+ {
+ for (Map.Entry<QName,Object> 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 <code>call-template</code>
+ * instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>choose</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>comment</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>copy</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>copy-of</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>current()</code>function.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>document()</code>function.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>document</code> 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 <code>element-available</code> function.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>element</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>for-each</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class ForEachNode
+ extends TemplateNode
+{
+
+ final Expr select;
+ final List<SortKey> sortKeys;
+
+ ForEachNode(Expr select, List<SortKey> sortKeys)
+ {
+ this.select = select;
+ this.sortKeys = sortKeys;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ int len = sortKeys.size();
+ List<SortKey> sortKeys2 = new ArrayList<SortKey>(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<Node> */
+ @SuppressWarnings("unchecked")
+ Collection<Node> ns = (Collection<Node>) ret;
+ List<Node> list = new ArrayList<Node>(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<SortKey> 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 <code>format-number()</code>function.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 &#x00a4; 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 <code>function-available</code> function.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>generate-id()</code>function.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>if</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>key()</code>function.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>message</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>number</code> instruction
+ * with no <code>value</code> expression, i.e. the value is computed from
+ * the document position of the context node.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>number</code> instruction
+ * with a <code>value</code> expression.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <code>otherwise</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class ParameterNode
+ extends TemplateNode
+ implements Comparable<ParameterNode>
+{
+
+ 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 <code>processing-instruction</code>
+ * instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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;
+
+/**
+ * <p>
+ * An XSL sort key, as specified by section 10 of the XSL
+ * Transformations specification. This takes the form:
+ * </p>
+ * <pre>
+ * &lt;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;
+ * </pre>
+ * <p>
+ * Note that all but the selection expression are optional,
+ * and so may be {@code null}.
+ * </p>
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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 &lt;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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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("<![CDATA[" + head + "]]>"));
+ value = value.substring(bbk + 2);
+ bbk = value.indexOf("]]>");
+ }
+ // Write final tail value
+ out.write(encodeText("<![CDATA[" + value + "]]>"));
+ break;
+ case Node.COMMENT_NODE:
+ value = "<!--" + node.getNodeValue() + "-->";
+ 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 = "<?" + node.getNodeName() + " " + node.getNodeValue() + "?>";
+ 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("&lt;");
+ }
+ else if (c == '>')
+ {
+ if (buf == null)
+ buf = new CPStringBuilder(text.substring(0, i));
+ buf.append("&gt;");
+ }
+ 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("&amp;");
+ }
+ }
+ else if (c == '\'' && inAttr)
+ {
+ if (buf == null)
+ buf = new CPStringBuilder(text.substring(0, i));
+ if (mode == Stylesheet.OUTPUT_HTML)
+ // HTML does not define &apos;, use character entity ref
+ buf.append("&#x27;");
+ else
+ buf.append("&apos;");
+ }
+ else if (c == '"' && inAttr)
+ {
+ if (buf == null)
+ buf = new CPStringBuilder(text.substring(0, i));
+ buf.append("&quot;");
+ }
+ 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class StrippingInstruction
+{
+
+ final NameTest element;
+ final int precedence;
+
+ StrippingInstruction(NameTest element, int precedence)
+ {
+ this.element = element;
+ this.precedence = precedence;
+ }
+
+ /**
+ * Returns the <i>default priority</i> 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 <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+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<String> extensionElementPrefixes;
+ Collection<String> excludeResultPrefixes;
+
+ /**
+ * Set of element names for which we should strip whitespace.
+ */
+ Set<StrippingInstruction> stripSpace;
+
+ /**
+ * Set of element names for which we should preserve whitespace.
+ */
+ Set<StrippingInstruction> preserveSpace;
+
+ /**
+ * Output options.
+ */
+ Node output;
+ int outputMethod;
+ String outputVersion;
+ String outputEncoding;
+ boolean outputOmitXmlDeclaration;
+ boolean outputStandalone;
+ String outputPublicId;
+ String outputSystemId;
+ Collection<String> outputCdataSectionElements;
+ boolean outputIndent;
+ String outputMediaType;
+
+ /**
+ * Keys.
+ */
+ Collection<Key> keys;
+
+ /**
+ * Decimal formats.
+ */
+ Map<String,DecimalFormat> decimalFormats;
+
+ /**
+ * Namespace aliases.
+ */
+ Map<String,String> namespaceAliases;
+
+ /**
+ * Attribute-sets.
+ */
+ List<AttributeSet> attributeSets;
+
+ /**
+ * Variables.
+ */
+ List<ParameterNode> variables;
+
+ /**
+ * Variable and parameter bindings.
+ */
+ Bindings bindings;
+
+ /**
+ * Templates.
+ */
+ LinkedList<Template> templates;
+
+ TemplateNode builtInNodeTemplate;
+ TemplateNode builtInTextTemplate;
+
+ /**
+ * Holds the current node while parsing.
+ * Necessary to associate the document function with its declaring node,
+ * to resolve namespaces, and to maintain the current node for the
+ * current() function.
+ */
+ Node current;
+
+ /**
+ * Set by a terminating message.
+ */
+ transient boolean terminated;
+
+ /**
+ * Current template in force.
+ */
+ transient Template currentTemplate;
+
+ Stylesheet(TransformerFactoryImpl factory,
+ Stylesheet parent,
+ Document doc,
+ String systemId,
+ int precedence)
+ throws TransformerConfigurationException
+ {
+ this.factory = factory;
+ this.systemId = systemId;
+ this.precedence = precedence;
+ this.parent = parent;
+ extensionElementPrefixes = new HashSet<String>();
+ excludeResultPrefixes = new HashSet<String>();
+ stripSpace = new LinkedHashSet<StrippingInstruction>();
+ preserveSpace = new LinkedHashSet<StrippingInstruction>();
+ outputCdataSectionElements = new LinkedHashSet<String>();
+ xpath = (XPathImpl) factory.xpathFactory.newXPath();
+ xpath.setNamespaceContext(this);
+ if (parent == null)
+ {
+ bindings = new Bindings(this);
+ attributeSets = new LinkedList<AttributeSet>();
+ variables = new LinkedList<ParameterNode>();
+ namespaceAliases = new LinkedHashMap<String,String>();
+ templates = new LinkedList<Template>();
+ keys = new LinkedList<Key>();
+ decimalFormats = new LinkedHashMap<String,DecimalFormat>();
+ initDefaultDecimalFormat();
+ xpath.setXPathFunctionResolver(this);
+ }
+ else
+ {
+ /* Test for import circularity */
+ for (Stylesheet ctx = this; ctx.parent != null; ctx = ctx.parent)
+ {
+ if (systemId != null && systemId.equals(ctx.parent.systemId))
+ {
+ String msg = "circularity importing " + systemId;
+ throw new TransformerConfigurationException(msg);
+ }
+ }
+ /* OK */
+ Stylesheet root = getRootStylesheet();
+ bindings = root.bindings;
+ attributeSets = root.attributeSets;
+ variables = root.variables;
+ namespaceAliases = root.namespaceAliases;
+ templates = root.templates;
+ keys = root.keys;
+ decimalFormats = root.decimalFormats;
+ xpath.setXPathFunctionResolver(root);
+ }
+ xpath.setXPathVariableResolver(bindings);
+
+ Test anyNode = new NodeTypeTest((short) 0);
+ List<Test> tests = Collections.singletonList(anyNode);
+ builtInNodeTemplate =
+ new ApplyTemplatesNode(new Selector(Selector.CHILD, tests),
+ null, null, null, true);
+ builtInTextTemplate =
+ new ValueOfNode(new Selector(Selector.SELF, tests),
+ false);
+
+ parse(doc.getDocumentElement(), true);
+ current = doc; // Alow namespace resolution during processing
+
+ debug = ("yes".equals(System.getProperty("xsl.debug")));
+
+ if (debug)
+ {
+ System.err.println("Stylesheet: " + doc.getDocumentURI());
+ for (Template t : templates)
+ {
+ t.list(System.err);
+ System.err.println("--------------------");
+ }
+ }
+ }
+
+ Stylesheet getRootStylesheet()
+ {
+ Stylesheet stylesheet = this;
+ while (stylesheet.parent != null)
+ stylesheet = stylesheet.parent;
+ return stylesheet;
+ }
+
+ void initDefaultDecimalFormat()
+ {
+ DecimalFormat defaultDecimalFormat = new DecimalFormat();
+ DecimalFormatSymbols symbols = new DecimalFormatSymbols();
+ symbols.setDecimalSeparator('.');
+ symbols.setGroupingSeparator(',');
+ symbols.setPercent('%');
+ symbols.setPerMill('\u2030');
+ symbols.setZeroDigit('0');
+ symbols.setDigit('#');
+ symbols.setPatternSeparator(';');
+ symbols.setInfinity("Infinity");
+ symbols.setNaN("NaN");
+ symbols.setMinusSign('-');
+ defaultDecimalFormat.setDecimalFormatSymbols(symbols);
+ decimalFormats.put(null, defaultDecimalFormat);
+ }
+
+ // -- Cloneable --
+
+ public Object clone()
+ {
+ try
+ {
+ Stylesheet clone = (Stylesheet) super.clone();
+ clone.bindings = (Bindings) bindings.clone();
+
+ LinkedList<Template> templates2 = new LinkedList<Template>();
+ for (Template t : templates)
+ {
+ templates2.add(t.clone(clone));
+ }
+ clone.templates = templates2;
+
+ LinkedList<AttributeSet> attributeSets2 = new LinkedList<AttributeSet>();
+ for (AttributeSet as : attributeSets)
+ {
+ attributeSets2.add(as.clone(clone));
+ }
+ clone.attributeSets = attributeSets2;
+
+ LinkedList<ParameterNode> variables2 = new LinkedList<ParameterNode>();
+ for (ParameterNode var : variables)
+ {
+ variables2.add(var.clone(clone));
+ }
+ clone.variables = variables2;
+
+ LinkedList<Key> keys2 = new LinkedList<Key>();
+ for (Key k : keys)
+ {
+ keys2.add(k.clone(clone));
+ }
+ clone.keys = keys2;
+
+ return clone;
+ }
+ catch (CloneNotSupportedException e)
+ {
+ throw new Error(e.getMessage());
+ }
+ }
+
+ // -- Variable evaluation --
+
+ void initTopLevelVariables(Node context)
+ throws TransformerException
+ {
+ current = context;
+ // Sort the variables into order
+ // See XSLT 11.4: "If the template or expression specifying the value of
+ // a global variable x references a global variable y, then the value
+ // for y must be computed before the value of x."
+ List<ParameterNode> topLevel = new ArrayList<ParameterNode>(variables);
+ Collections.sort(topLevel);
+ for (ParameterNode var : topLevel)
+ {
+ bindings.set(var.name,
+ var.getValue(this, null, context, 1, 1),
+ var.type);
+ }
+ current = null;
+ }
+
+ // -- NamespaceContext --
+
+ public String getNamespaceURI(String prefix)
+ {
+ return (current == null) ? null : current.lookupNamespaceURI(prefix);
+ }
+
+ public String getPrefix(String namespaceURI)
+ {
+ return (current == null) ? null : current.lookupPrefix(namespaceURI);
+ }
+
+ public Iterator<String> getPrefixes(String namespaceURI)
+ {
+ // TODO
+ return Collections.singleton(getPrefix(namespaceURI)).iterator();
+ }
+
+ final QName getQName(String name)
+ {
+ String localName = name, uri = null, prefix = null;
+ int ci = name.indexOf(':');
+ if (ci != -1)
+ {
+ prefix = name.substring(0, ci);
+ localName = name.substring(ci + 1);
+ uri = getNamespaceURI(prefix);
+ }
+ return new QName(uri, localName, prefix);
+ }
+
+ // -- Template selection --
+
+ TemplateNode getTemplate(QName mode, Node context, boolean applyImports)
+ throws TransformerException
+ {
+ if (debug)
+ System.err.println("getTemplate: mode="+mode+" context="+context);
+ Template selected = null;
+ for (Template t : templates)
+ {
+ boolean isMatch = t.matches(mode, context);
+ if (applyImports)
+ {
+ if (currentTemplate == null)
+ {
+ String msg = "current template may not be null " +
+ "during apply-imports";
+ throw new TransformerException(msg);
+ }
+ if (!currentTemplate.imports(t))
+ isMatch = false;
+ }
+ //System.err.println("\t"+context+" "+t+"="+isMatch);
+ if (isMatch)
+ {
+ // Conflict resolution
+ // @see http://www.w3.org/TR/xslt#conflict
+ if (selected == null)
+ selected = t;
+ else
+ {
+ if (t.precedence < selected.precedence ||
+ t.priority < selected.priority)
+ continue;
+ selected = t;
+ }
+ }
+ }
+ if (selected == null)
+ {
+ // Apply built-in template
+ // Current template is unchanged
+ if (debug)
+ System.err.println("\tbuiltInTemplate context="+context);
+ switch (context.getNodeType())
+ {
+ case Node.ELEMENT_NODE:
+ case Node.DOCUMENT_NODE:
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ case Node.COMMENT_NODE:
+ return builtInNodeTemplate;
+ case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ case Node.ATTRIBUTE_NODE:
+ return builtInTextTemplate;
+ default:
+ return null;
+ }
+ }
+ // Set current template
+ currentTemplate = selected;
+ if (debug)
+ System.err.println("\ttemplate="+currentTemplate+" context="+context);
+ return currentTemplate.node;
+ }
+
+ TemplateNode getTemplate(QName mode, QName name)
+ throws TransformerException
+ {
+ Template selected = null;
+ for (Template t : templates)
+ {
+ boolean isMatch = t.matches(name);
+ if (isMatch)
+ {
+ // Conflict resolution
+ // @see http://www.w3.org/TR/xslt#conflict
+ if (selected == null)
+ selected = t;
+ else
+ {
+ if (t.precedence < selected.precedence ||
+ t.priority < selected.priority)
+ continue;
+ selected = t;
+ }
+ }
+ }
+ if (selected == null)
+ return null;
+ return selected.node;
+ }
+
+ /**
+ * template
+ */
+ final Template parseTemplate(Node node, NamedNodeMap attrs)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ String n = getAttribute(attrs, "name");
+ QName name = (n == null) ? null : getQName(n);
+ String m = getAttribute(attrs, "match");
+ Pattern match = null;
+ if (m != null)
+ {
+ try
+ {
+ match = (Pattern) xpath.compile(m);
+ }
+ catch (ClassCastException e)
+ {
+ String msg = "illegal pattern: " + m;
+ throw new TransformerConfigurationException(msg);
+ }
+ }
+ String p = getAttribute(attrs, "priority");
+ String mm = getAttribute(attrs, "mode");
+ QName mode = (mm == null) ? null : getQName(mm);
+ Node children = node.getFirstChild();
+ return new Template(this, name, match, parse(children),
+ precedence, p, mode);
+ }
+
+ /**
+ * output
+ */
+ final void parseOutput(Node node, NamedNodeMap attrs)
+ throws TransformerConfigurationException
+ {
+ output = node;
+ String method = getAttribute(attrs, "method");
+ if ("xml".equals(method) || method == null)
+ outputMethod = OUTPUT_XML;
+ else if ("html".equals(method))
+ outputMethod = OUTPUT_HTML;
+ else if ("text".equals(method))
+ outputMethod = OUTPUT_TEXT;
+ else
+ {
+ String msg = "unsupported output method: " + method;
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(msg, l);
+ }
+ outputPublicId = getAttribute(attrs, "doctype-public");
+ outputSystemId = getAttribute(attrs, "doctype-system");
+ outputEncoding = getAttribute(attrs, "encoding");
+ String indent = getAttribute(attrs, "indent");
+ if (indent != null)
+ outputIndent = "yes".equals(indent);
+ outputVersion = getAttribute(attrs, "version");
+ String omitXmlDecl = getAttribute(attrs, "omit-xml-declaration");
+ if (omitXmlDecl != null)
+ outputOmitXmlDeclaration = "yes".equals(omitXmlDecl);
+ String standalone = getAttribute(attrs, "standalone");
+ if (standalone != null)
+ outputStandalone = "yes".equals(standalone);
+ outputMediaType = getAttribute(attrs, "media-type");
+ String cdataSectionElements =
+ getAttribute(attrs, "cdata-section-elements");
+ if (cdataSectionElements != null)
+ {
+ StringTokenizer st = new StringTokenizer(cdataSectionElements, " ");
+ while (st.hasMoreTokens())
+ outputCdataSectionElements.add(st.nextToken());
+ }
+ }
+
+ /**
+ * key
+ */
+ final void parseKey(Node node, NamedNodeMap attrs)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ String n = getRequiredAttribute(attrs, "name", node);
+ String m = getRequiredAttribute(attrs, "match", node);
+ String u = getRequiredAttribute(attrs, "use", node);
+ QName name = getQName(n);
+ Expr use = (Expr) xpath.compile(u);
+ try
+ {
+ Pattern match = (Pattern) xpath.compile(m);
+ Key key = new Key(name, match, use);
+ keys.add(key);
+ }
+ catch (ClassCastException e)
+ {
+ throw new TransformerConfigurationException("invalid pattern: " + m);
+ }
+ }
+
+ /**
+ * decimal-format
+ */
+ final void parseDecimalFormat(Node node, NamedNodeMap attrs)
+ throws TransformerConfigurationException
+ {
+ String dfName = getAttribute(attrs, "name");
+ DecimalFormat df = new DecimalFormat();
+ DecimalFormatSymbols symbols = new DecimalFormatSymbols();
+ symbols.setDecimalSeparator(parseDFChar(attrs, "decimal-separator", '.'));
+ symbols.setGroupingSeparator(parseDFChar(attrs, "grouping-separator", ','));
+ symbols.setInfinity(parseDFString(attrs, "infinity", "Infinity"));
+ symbols.setMinusSign(parseDFChar(attrs, "minus-sign", '-'));
+ symbols.setNaN(parseDFString(attrs, "NaN", "NaN"));
+ symbols.setPercent(parseDFChar(attrs, "percent", '%'));
+ symbols.setPerMill(parseDFChar(attrs, "per-mille", '\u2030'));
+ symbols.setZeroDigit(parseDFChar(attrs, "zero-digit", '0'));
+ symbols.setDigit(parseDFChar(attrs, "digit", '#'));
+ symbols.setPatternSeparator(parseDFChar(attrs, "pattern-separator", ';'));
+ df.setDecimalFormatSymbols(symbols);
+ decimalFormats.put(dfName, df);
+ }
+
+ private final char parseDFChar(NamedNodeMap attrs, String name, char def)
+ throws TransformerConfigurationException
+ {
+ Node attr = attrs.getNamedItem(name);
+ try
+ {
+ return (attr == null) ? def : attr.getNodeValue().charAt(0);
+ }
+ catch (StringIndexOutOfBoundsException e)
+ {
+ throw new TransformerConfigurationException("empty attribute '" +
+ name +
+ "' in decimal-format", e);
+ }
+ }
+
+ private final String parseDFString(NamedNodeMap attrs, String name,
+ String def)
+ {
+ Node attr = attrs.getNamedItem(name);
+ return (attr == null) ? def : attr.getNodeValue();
+ }
+
+ /**
+ * namespace-alias
+ */
+ final void parseNamespaceAlias(Node node, NamedNodeMap attrs)
+ throws TransformerConfigurationException
+ {
+ String sp = getRequiredAttribute(attrs, "stylesheet-prefix", node);
+ String rp = getRequiredAttribute(attrs, "result-prefix", node);
+ namespaceAliases.put(sp, rp);
+ }
+
+ /**
+ * attribute-set
+ */
+ final void parseAttributeSet(Node node, NamedNodeMap attrs)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ TemplateNode children = parse(node.getFirstChild());
+ String name = getRequiredAttribute(attrs, "name", node);
+ String uas = getAttribute(attrs, "use-attribute-sets");
+ attributeSets.add(new AttributeSet(children, name, uas));
+ }
+
+ /**
+ * Parse top-level elements.
+ */
+ void parse(Node node, boolean root)
+ throws TransformerConfigurationException
+ {
+ while (node != null)
+ {
+ current = node;
+ doParse(node, root);
+ node = node.getNextSibling();
+ }
+ }
+
+ void doParse(Node node, boolean root)
+ throws TransformerConfigurationException
+ {
+ try
+ {
+ String namespaceUri = node.getNamespaceURI();
+ if (XSL_NS.equals(namespaceUri) &&
+ node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ String name = node.getLocalName();
+ NamedNodeMap attrs = node.getAttributes();
+ if ("stylesheet".equals(name))
+ {
+ version = getAttribute(attrs, "version");
+ String eep = getAttribute(attrs, "extension-element-prefixes");
+ if (eep != null)
+ {
+ StringTokenizer st = new StringTokenizer(eep);
+ while (st.hasMoreTokens())
+ {
+ extensionElementPrefixes.add(st.nextToken());
+ }
+ }
+ String erp = getAttribute(attrs, "exclude-result-prefixes");
+ if (erp != null)
+ {
+ StringTokenizer st = new StringTokenizer(erp);
+ while (st.hasMoreTokens())
+ {
+ excludeResultPrefixes.add(st.nextToken());
+ }
+ }
+ parse(node.getFirstChild(), false);
+ }
+ else if ("template".equals(name))
+ templates.add(parseTemplate(node, attrs));
+ else if ("param".equals(name) ||
+ "variable".equals(name))
+ {
+ int type = "variable".equals(name) ?
+ Bindings.VARIABLE : Bindings.PARAM;
+ TemplateNode content = parse(node.getFirstChild());
+ QName paramName =
+ getQName(getRequiredAttribute(attrs, "name", node));
+ String select = getAttribute(attrs, "select");
+ ParameterNode param;
+ if (select != null && select.length() > 0)
+ {
+ if (content != null)
+ {
+ String msg = "parameter '" + paramName +
+ "' has both select and content";
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(msg, l);
+ }
+ Expr expr = (Expr) xpath.compile(select);
+ param = new ParameterNode(paramName, expr, type);
+ }
+ else
+ {
+ param = new ParameterNode(paramName, null, type);
+ param.children = content;
+ }
+ variables.add(param);
+ }
+ else if ("include".equals(name) || "import".equals(name))
+ {
+ int delta = "import".equals(name) ? -1 : 0;
+ String href = getRequiredAttribute(attrs, "href", node);
+ Source source;
+ synchronized (factory.resolver)
+ {
+ if (transformer != null)
+ {
+ factory.resolver
+ .setUserResolver(transformer.getURIResolver());
+ factory.resolver
+ .setUserListener(transformer.getErrorListener());
+ }
+ source = factory.resolver.resolve(systemId, href);
+ }
+ factory.newStylesheet(source, precedence + delta, this);
+ }
+ else if ("output".equals(name))
+ parseOutput(node, attrs);
+ else if ("preserve-space".equals(name))
+ {
+ String elements =
+ getRequiredAttribute(attrs, "elements", node);
+ StringTokenizer st = new StringTokenizer(elements,
+ " \t\n\r");
+ while (st.hasMoreTokens())
+ {
+ NameTest element = parseNameTest(st.nextToken());
+ preserveSpace.add(new StrippingInstruction(element,
+ precedence));
+ }
+ }
+ else if ("strip-space".equals(name))
+ {
+ String elements =
+ getRequiredAttribute(attrs, "elements", node);
+ StringTokenizer st = new StringTokenizer(elements,
+ " \t\n\r");
+ while (st.hasMoreTokens())
+ {
+ NameTest element = parseNameTest(st.nextToken());
+ stripSpace.add(new StrippingInstruction(element,
+ precedence));
+ }
+ }
+ else if ("key".equals(name))
+ parseKey(node, attrs);
+ else if ("decimal-format".equals(name))
+ parseDecimalFormat(node, attrs);
+ else if ("namespace-alias".equals(name))
+ parseNamespaceAlias(node, attrs);
+ else if ("attribute-set".equals(name))
+ parseAttributeSet(node, attrs);
+ }
+ else if (root)
+ {
+ // Literal document element
+ Attr versionNode =
+ ((Element)node).getAttributeNodeNS(XSL_NS, "version");
+ if (versionNode == null)
+ {
+ String msg = "no xsl:version attribute on literal result node";
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(msg, l);
+ }
+ version = versionNode.getValue();
+ Node rootClone = node.cloneNode(true);
+ NamedNodeMap attrs = rootClone.getAttributes();
+ attrs.removeNamedItemNS(XSL_NS, "version");
+ templates.add(new Template(this, null, new Root(),
+ parse(rootClone),
+ precedence,
+ null,
+ null));
+ }
+ else
+ {
+ // Skip unknown elements, text, comments, etc
+ }
+ }
+ catch (TransformerException e)
+ {
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(e.getMessage(), l, e);
+ }
+ catch (DOMException e)
+ {
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(e.getMessage(), l, e);
+ }
+ catch (XPathExpressionException e)
+ {
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(e.getMessage(), l, e);
+ }
+ }
+
+ final NameTest parseNameTest(String token)
+ {
+ if ("*".equals(token))
+ return new NameTest(null, true, true);
+ else if (token.endsWith(":*"))
+ {
+ QName qName = getQName(token);
+ return new NameTest(qName, true, false);
+ }
+ else
+ {
+ QName qName = getQName(token);
+ return new NameTest(qName, false, false);
+ }
+ }
+
+ final TemplateNode parseAttributeValueTemplate(String value, Node source)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ current = source;
+ // Tokenize
+ int len = value.length();
+ int off = 0;
+ List<String> tokens = new ArrayList<String>(); // text tokens
+ List<Boolean> types = new ArrayList<Boolean>(); // literal or expression
+ int depth = 0;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == '{')
+ {
+ if (i < (len - 1) && value.charAt(i + 1) == '{')
+ {
+ tokens.add(value.substring(off, i + 1));
+ types.add(Boolean.FALSE);
+ i++;
+ off = i + 1;
+ continue;
+ }
+ if (depth == 0)
+ {
+ if (i - off > 0)
+ {
+ tokens.add(value.substring(off, i));
+ types.add(Boolean.FALSE);
+ }
+ off = i + 1;
+ }
+ depth++;
+ }
+ else if (c == '}')
+ {
+ if (i < (len - 1) && value.charAt(i + 1) == '}')
+ {
+ tokens.add(value.substring(off, i + 1));
+ types.add(Boolean.FALSE);
+ i++;
+ off = i + 1;
+ continue;
+ }
+ if (depth == 1)
+ {
+ if (i - off > 0)
+ {
+ tokens.add(value.substring(off, i));
+ types.add(Boolean.TRUE);
+ }
+ else
+ {
+ String msg = "attribute value template " +
+ "must contain expression: " + value;
+ DOMSourceLocator l = new DOMSourceLocator(source);
+ throw new TransformerConfigurationException(msg, l);
+ }
+ off = i + 1;
+ }
+ depth--;
+ }
+ }
+ if (depth > 0)
+ {
+ String msg = "invalid attribute value template: " + value;
+ throw new TransformerConfigurationException(msg);
+ }
+ if (len - off > 0)
+ {
+ // Trailing text
+ tokens.add(value.substring(off));
+ types.add(Boolean.FALSE);
+ }
+
+ // Construct template node tree
+ TemplateNode ret = null;
+ Document doc = source.getOwnerDocument();
+ len = tokens.size();
+ for (int i = len - 1; i >= 0; i--)
+ {
+ String token = tokens.get(i);
+ Boolean type = types.get(i);
+ if (type == Boolean.TRUE)
+ {
+ // Expression text
+ Expr select = (Expr) xpath.compile(token);
+ TemplateNode ret2 = new ValueOfNode(select, false);
+ ret2.next = ret;
+ ret = ret2;
+ }
+ else
+ {
+ // Verbatim text
+ TemplateNode ret2 = new LiteralNode(doc.createTextNode(token));
+ ret2.next = ret;
+ ret = ret2;
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * Whitespace stripping.
+ * @param text the text node
+ * @param source true if a source node, false if a stylesheet text node
+ * @see http://www.w3.org/TR/xslt#strip
+ */
+ boolean isPreserved(Text text, boolean source)
+ throws TransformerConfigurationException
+ {
+ // Check characters in text
+ String value = text.getData();
+ if (value != null)
+ {
+ int len = value.length();
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c != 0x20 && c != 0x09 && c != 0x0a && c != 0x0d)
+ return true;
+ }
+ }
+ // Check parent node
+ Node ctx = text.getParentNode();
+ if (source)
+ {
+ // Source document text node
+ boolean preserve = true;
+ float psPriority = 0.0f, ssPriority = 0.0f;
+ if (!stripSpace.isEmpty())
+ {
+ // Conflict resolution
+ StrippingInstruction ssi = null, psi = null;
+ for (StrippingInstruction si : stripSpace)
+ {
+ if (si.element.matches(ctx, 1, 1))
+ {
+ if (ssi != null)
+ {
+ if (si.precedence < ssi.precedence)
+ continue;
+ float p = si.getPriority();
+ if (p < ssPriority)
+ continue;
+ }
+ ssi = si;
+ }
+ }
+ for (StrippingInstruction si : preserveSpace)
+ {
+ if (si.element.matches(ctx, 1, 1))
+ {
+ if (psi != null)
+ {
+ if (si.precedence < psi.precedence)
+ continue;
+ float p = si.getPriority();
+ if (p < psPriority)
+ continue;
+ }
+ psi = si;
+ }
+ }
+ if (ssi != null)
+ {
+ if (psi != null)
+ {
+ if (psi.precedence < ssi.precedence)
+ preserve = false;
+ else if (psPriority < ssPriority)
+ preserve = false;
+ }
+ else
+ preserve = false;
+ }
+ }
+ if (preserve)
+ return true;
+ }
+ else
+ {
+ // Stylesheet text node
+ if (STYLESHEET_PRESERVE_TEXT.matches(ctx, 1, 1))
+ return true;
+ }
+ // Check whether any ancestor specified xml:space
+ while (ctx != null)
+ {
+ if (ctx.getNodeType() == Node.ELEMENT_NODE)
+ {
+ Element element = (Element) ctx;
+ String xmlSpace = element.getAttribute("xml:space");
+ if ("default".equals(xmlSpace))
+ break;
+ else if ("preserve".equals(xmlSpace))
+ return true;
+ else if (xmlSpace.length() > 0)
+ {
+ String msg = "Illegal value for xml:space: " + xmlSpace;
+ throw new TransformerConfigurationException(msg);
+ }
+ }
+ ctx = ctx.getParentNode();
+ }
+ return false;
+ }
+
+ public XPathFunction resolveFunction(QName name, int arity)
+ {
+ String uri = name.getNamespaceURI();
+ if (XSL_NS.equals(uri) || uri == null || uri.length() == 0)
+ {
+ String localName = name.getLocalPart();
+ if ("document".equals(localName) && (arity == 1 || arity == 2))
+ {
+ if (current == null)
+ throw new RuntimeException("current is null");
+ return new DocumentFunction(getRootStylesheet(), current);
+ }
+ else if ("key".equals(localName) && (arity == 2))
+ return new KeyFunction(getRootStylesheet());
+ else if ("format-number".equals(localName) &&
+ (arity == 2 || arity == 3))
+ return new FormatNumberFunction(getRootStylesheet());
+ else if ("current".equals(localName) && (arity == 0))
+ return new CurrentFunction(getRootStylesheet());
+ else if ("unparsed-entity-uri".equals(localName) && (arity == 1))
+ return new UnparsedEntityUriFunction();
+ else if ("generate-id".equals(localName) &&
+ (arity == 1 || arity == 0))
+ return new GenerateIdFunction();
+ else if ("system-property".equals(localName) && (arity == 1))
+ return new SystemPropertyFunction();
+ else if ("element-available".equals(localName) && (arity == 1))
+ return new ElementAvailableFunction(new NamespaceProxy(current));
+ else if ("function-available".equals(localName) && (arity == 1))
+ return new FunctionAvailableFunction(new NamespaceProxy(current));
+ }
+ return null;
+ }
+
+ // -- Parsing --
+
+ /**
+ * apply-templates
+ */
+ final TemplateNode parseApplyTemplates(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String m = getAttribute(attrs, "mode");
+ QName mode = (m == null) ? null : getQName(m);
+ String s = getAttribute(attrs, "select");
+ if (s == null)
+ s = "child::node()";
+ Node children = node.getFirstChild();
+ List<SortKey> sortKeys = parseSortKeys(children);
+ List<WithParam> withParams = parseWithParams(children);
+ Expr select = (Expr) xpath.compile(s);
+ return new ApplyTemplatesNode(select, mode,
+ sortKeys, withParams, false);
+ }
+
+ /**
+ * call-template
+ */
+ final TemplateNode parseCallTemplate(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String n = getRequiredAttribute(attrs, "name", node);
+ QName name = getQName(n);
+ Node children = node.getFirstChild();
+ List<WithParam> withParams = parseWithParams(children);
+ return new CallTemplateNode(name, withParams);
+ }
+
+ /**
+ * value-of
+ */
+ final TemplateNode parseValueOf(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String s = getRequiredAttribute(attrs, "select", node);
+ String doe = getAttribute(attrs, "disable-output-escaping");
+ boolean d = "yes".equals(doe);
+ Expr select = (Expr) xpath.compile(s);
+ return new ValueOfNode(select, d);
+ }
+
+ /**
+ * for-each
+ */
+ final TemplateNode parseForEach(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String s = getRequiredAttribute(attrs, "select", node);
+ Node children = node.getFirstChild();
+ List<SortKey> sortKeys = parseSortKeys(children);
+ Expr select = (Expr) xpath.compile(s);
+ ForEachNode ret = new ForEachNode(select, sortKeys);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * if
+ */
+ final TemplateNode parseIf(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String t = getRequiredAttribute(attrs, "test", node);
+ Expr test = (Expr) xpath.compile(t);
+ Node children = node.getFirstChild();
+ IfNode ret = new IfNode(test);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * when
+ */
+ final TemplateNode parseWhen(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String t = getRequiredAttribute(attrs, "test", node);
+ Expr test = (Expr) xpath.compile(t);
+ Node children = node.getFirstChild();
+ WhenNode ret = new WhenNode(test);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * element
+ */
+ final TemplateNode parseElement(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String name = getRequiredAttribute(attrs, "name", node);
+ String namespace = getAttribute(attrs, "namespace");
+ String uas = getAttribute(attrs, "use-attribute-sets");
+ TemplateNode n = parseAttributeValueTemplate(name, node);
+ TemplateNode ns = (namespace == null) ? null :
+ parseAttributeValueTemplate(namespace, node);
+ Node children = node.getFirstChild();
+ ElementNode ret = new ElementNode(n, ns, uas, node);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * attribute
+ */
+ final TemplateNode parseAttribute(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String name = getRequiredAttribute(attrs, "name", node);
+ String namespace = getAttribute(attrs, "namespace");
+ TemplateNode n = parseAttributeValueTemplate(name, node);
+ TemplateNode ns = (namespace == null) ? null :
+ parseAttributeValueTemplate(namespace, node);
+ Node children = node.getFirstChild();
+ AttributeNode ret = new AttributeNode(n, ns, node);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * text
+ */
+ final TemplateNode parseText(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String doe = getAttribute(attrs, "disable-output-escaping");
+ boolean d = "yes".equals(doe);
+ Node children = node.getFirstChild();
+ TextNode ret = new TextNode(d);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * copy
+ */
+ final TemplateNode parseCopy(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String uas = getAttribute(attrs, "use-attribute-sets");
+ Node children = node.getFirstChild();
+ CopyNode ret = new CopyNode(uas);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * processing-instruction
+ */
+ final TemplateNode parseProcessingInstruction(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String name = getRequiredAttribute(attrs, "name", node);
+ Node children = node.getFirstChild();
+ ProcessingInstructionNode ret = new ProcessingInstructionNode(name);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * number
+ */
+ final TemplateNode parseNumber(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String v = getAttribute(attrs, "value");
+ String ff = getAttribute(attrs, "format");
+ if (ff == null)
+ {
+ ff = "1";
+ }
+ TemplateNode format = parseAttributeValueTemplate(ff, node);
+ String lang = getAttribute(attrs, "lang");
+ String lv = getAttribute(attrs, "letter-value");
+ int letterValue = "traditional".equals(lv) ?
+ AbstractNumberNode.TRADITIONAL :
+ AbstractNumberNode.ALPHABETIC;
+ String gs = getAttribute(attrs, "grouping-separator");
+ String gz = getAttribute(attrs, "grouping-size");
+ int gz2 = (gz != null && gz.length() > 0) ?
+ Integer.parseInt(gz) : 1;
+ Node children = node.getFirstChild();
+ TemplateNode ret;
+ if (v != null && v.length() > 0)
+ {
+ Expr value = (Expr) xpath.compile(v);
+ ret = new NumberNode(value, format, lang,
+ letterValue, gs, gz2);
+ }
+ else
+ {
+ String l = getAttribute(attrs, "level");
+ int level =
+ "multiple".equals(l) ? NodeNumberNode.MULTIPLE :
+ "any".equals(l) ? NodeNumberNode.ANY :
+ NodeNumberNode.SINGLE;
+ String c = getAttribute(attrs, "count");
+ String f = getAttribute(attrs, "from");
+ Pattern count = null;
+ Pattern from = null;
+ if (c != null)
+ {
+ try
+ {
+ count = (Pattern) xpath.compile(c);
+ }
+ catch (ClassCastException e)
+ {
+ String msg = "invalid pattern: " + c;
+ throw new TransformerConfigurationException(msg);
+ }
+ }
+ if (f != null)
+ {
+ try
+ {
+ from = (Pattern) xpath.compile(f);
+ }
+ catch (ClassCastException e)
+ {
+ String msg = "invalid pattern: " + f;
+ throw new TransformerConfigurationException(msg);
+ }
+ }
+ ret = new NodeNumberNode(level, count, from,
+ format, lang,
+ letterValue, gs, gz2);
+ }
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * copy-of
+ */
+ final TemplateNode parseCopyOf(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String s = getRequiredAttribute(attrs, "select", node);
+ Expr select = (Expr) xpath.compile(s);
+ Node children = node.getFirstChild();
+ CopyOfNode ret = new CopyOfNode(select);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * message
+ */
+ final TemplateNode parseMessage(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String t = getAttribute(attrs, "terminate");
+ boolean terminate = "yes".equals(t);
+ Node children = node.getFirstChild();
+ MessageNode ret = new MessageNode(terminate);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ /**
+ * Parse template-level elements.
+ */
+ final TemplateNode parse(Node node)
+ throws TransformerConfigurationException
+ {
+ TemplateNode first = null;
+ TemplateNode previous = null;
+ while (node != null)
+ {
+ Node next = node.getNextSibling();
+ TemplateNode tnode = doParse(node);
+ if (tnode != null)
+ {
+ if (first == null)
+ first = tnode;
+ if (previous != null)
+ previous.next = tnode;
+ previous = tnode;
+ }
+ node = next;
+ }
+ return first;
+ }
+
+ private final TemplateNode doParse(Node node)
+ throws TransformerConfigurationException
+ {
+ // Hack to associate the document function with its declaring node
+ current = node;
+ try
+ {
+ String namespaceUri = node.getNamespaceURI();
+ if (Stylesheet.XSL_NS.equals(namespaceUri) &&
+ Node.ELEMENT_NODE == node.getNodeType())
+ {
+ String name = node.getLocalName();
+ if ("apply-templates".equals(name))
+ return parseApplyTemplates(node);
+ else if ("call-template".equals(name))
+ return parseCallTemplate(node);
+ else if ("value-of".equals(name))
+ return parseValueOf(node);
+ else if ("for-each".equals(name))
+ return parseForEach(node);
+ else if ("if".equals(name))
+ return parseIf(node);
+ else if ("choose".equals(name))
+ {
+ Node children = node.getFirstChild();
+ ChooseNode ret = new ChooseNode();
+ ret.children = parse(children);
+ return ret;
+ }
+ else if ("when".equals(name))
+ return parseWhen(node);
+ else if ("otherwise".equals(name))
+ {
+ Node children = node.getFirstChild();
+ OtherwiseNode ret = new OtherwiseNode();
+ ret.children = parse(children);
+ return ret;
+ }
+ else if ("element".equals(name))
+ return parseElement(node);
+ else if ("attribute".equals(name))
+ return parseAttribute(node);
+ else if ("text".equals(name))
+ return parseText(node);
+ else if ("copy".equals(name))
+ return parseCopy(node);
+ else if ("processing-instruction".equals(name))
+ return parseProcessingInstruction(node);
+ else if ("comment".equals(name))
+ {
+ Node children = node.getFirstChild();
+ CommentNode ret = new CommentNode();
+ ret.children = parse(children);
+ return ret;
+ }
+ else if ("number".equals(name))
+ return parseNumber(node);
+ else if ("param".equals(name) ||
+ "variable".equals(name))
+ {
+ int type = "variable".equals(name) ?
+ Bindings.VARIABLE : Bindings.PARAM;
+ NamedNodeMap attrs = node.getAttributes();
+ Node children = node.getFirstChild();
+ TemplateNode content = parse(children);
+ QName paramName =
+ getQName(getRequiredAttribute(attrs, "name", node));
+ String select = getAttribute(attrs, "select");
+ ParameterNode ret;
+ if (select != null)
+ {
+ if (content != null)
+ {
+ String msg = "parameter '" + paramName +
+ "' has both select and content";
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(msg, l);
+ }
+ Expr expr = (Expr) xpath.compile(select);
+ ret = new ParameterNode(paramName, expr, type);
+ }
+ else
+ {
+ ret = new ParameterNode(paramName, null, type);
+ ret.children = content;
+ }
+ return ret;
+ }
+ else if ("copy-of".equals(name))
+ return parseCopyOf(node);
+ else if ("message".equals(name))
+ return parseMessage(node);
+ else if ("apply-imports".equals(name))
+ {
+ Node children = node.getFirstChild();
+ ApplyImportsNode ret = new ApplyImportsNode();
+ ret.children = parse(children);
+ return ret;
+ }
+ else
+ {
+ // xsl:fallback
+ // Pass over any other XSLT nodes
+ return null;
+ }
+ }
+ String prefix = node.getPrefix();
+ if (extensionElementPrefixes.contains(prefix))
+ {
+ // Check for xsl:fallback
+ for (Node ctx = node.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ String ctxUri = ctx.getNamespaceURI();
+ if (XSL_NS.equals(ctxUri) &&
+ "fallback".equals(ctx.getLocalName()))
+ {
+ ctx = ctx.getFirstChild();
+ return (ctx == null) ? null : parse(ctx);
+ }
+ }
+ // Otherwise pass over extension element
+ return null;
+ }
+ switch (node.getNodeType())
+ {
+ case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ // Determine whether to strip whitespace
+ Text text = (Text) node;
+ if (!isPreserved(text, false))
+ {
+ // Strip
+ text.getParentNode().removeChild(text);
+ return null;
+ }
+ break;
+ case Node.COMMENT_NODE:
+ // Ignore comments
+ return null;
+ case Node.ELEMENT_NODE:
+ // Check for attribute value templates and use-attribute-sets
+ NamedNodeMap attrs = node.getAttributes();
+ boolean convert = false;
+ String useAttributeSets = null;
+ int len = attrs.getLength();
+ for (int i = 0; i < len; i++)
+ {
+ Node attr = attrs.item(i);
+ String value = attr.getNodeValue();
+ if (Stylesheet.XSL_NS.equals(attr.getNamespaceURI()) &&
+ "use-attribute-sets".equals(attr.getLocalName()))
+ {
+ useAttributeSets = value;
+ convert = true;
+ break;
+ }
+ int start = value.indexOf('{');
+ int end = value.indexOf('}');
+ if (start != -1 || end != -1)
+ {
+ convert = true;
+ break;
+ }
+ }
+ if (convert)
+ {
+ // Create an element-producing template node instead
+ // with appropriate attribute-producing child template nodes
+ Node children = node.getFirstChild();
+ TemplateNode child = parse(children);
+ for (int i = 0; i < len; i++)
+ {
+ Node attr = attrs.item(i);
+ String ans = attr.getNamespaceURI();
+ String aname = attr.getNodeName();
+ if (Stylesheet.XSL_NS.equals(ans) &&
+ "use-attribute-sets".equals(attr.getLocalName()))
+ continue;
+ String value = attr.getNodeValue();
+ TemplateNode grandchild =
+ parseAttributeValueTemplate(value, node);
+ TemplateNode n =
+ parseAttributeValueTemplate(aname, node);
+ TemplateNode ns = (ans == null) ? null :
+ parseAttributeValueTemplate(ans, node);
+ TemplateNode newChild = new AttributeNode(n, ns, attr);
+ newChild.children = grandchild;
+ newChild.next = child;
+ child = newChild;
+ }
+ String ename = node.getNodeName();
+ TemplateNode n = parseAttributeValueTemplate(ename, node);
+ //TemplateNode ns = (namespaceUri == null) ? null :
+ // parseAttributeValueTemplate(namespaceUri, node);
+ TemplateNode ns = null;
+ ElementNode ret = new ElementNode(n, ns, useAttributeSets,
+ node);
+ ret.children = child;
+ return ret;
+ }
+ // Otherwise fall through
+ break;
+ }
+ }
+ catch (XPathExpressionException e)
+ {
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(e.getMessage(), l, e);
+ }
+ Node children = node.getFirstChild();
+ LiteralNode ret = new LiteralNode(node);
+ ret.children = parse(children);
+ return ret;
+ }
+
+ final List<SortKey> parseSortKeys(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ List<SortKey> ret = new LinkedList<SortKey>();
+ while (node != null)
+ {
+ String namespaceUri = node.getNamespaceURI();
+ if (Stylesheet.XSL_NS.equals(namespaceUri) &&
+ Node.ELEMENT_NODE == node.getNodeType() &&
+ "sort".equals(node.getLocalName()))
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String s = getAttribute(attrs, "select");
+ if (s == null)
+ s = ".";
+ Expr select = (Expr) xpath.compile(s);
+ String l = getAttribute(attrs, "lang");
+ TemplateNode lang = (l == null) ? null :
+ parseAttributeValueTemplate(l, node);
+ String dt = getAttribute(attrs, "data-type");
+ TemplateNode dataType = (dt == null) ? null :
+ parseAttributeValueTemplate(dt, node);
+ String o = getAttribute(attrs, "order");
+ TemplateNode order = (o == null) ? null :
+ parseAttributeValueTemplate(o, node);
+ String co = getAttribute(attrs, "case-order");
+ TemplateNode caseOrder = (co == null) ? null :
+ parseAttributeValueTemplate(co, node);
+ ret.add(new SortKey(select, lang, dataType, order, caseOrder));
+ }
+ node = node.getNextSibling();
+ }
+ return ret;
+ }
+
+ final List<WithParam> parseWithParams(Node node)
+ throws TransformerConfigurationException, XPathExpressionException
+ {
+ List<WithParam> ret = new LinkedList<WithParam>();
+ while (node != null)
+ {
+ String namespaceUri = node.getNamespaceURI();
+ if (Stylesheet.XSL_NS.equals(namespaceUri) &&
+ Node.ELEMENT_NODE == node.getNodeType() &&
+ "with-param".equals(node.getLocalName()))
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ TemplateNode content = parse(node.getFirstChild());
+ QName name =
+ getQName(getRequiredAttribute(attrs, "name", node));
+ String select = getAttribute(attrs, "select");
+ if (select != null)
+ {
+ if (content != null)
+ {
+ String msg = "parameter '" + name +
+ "' has both select and content";
+ DOMSourceLocator l = new DOMSourceLocator(node);
+ throw new TransformerConfigurationException(msg, l);
+ }
+ Expr expr = (Expr) xpath.compile(select);
+ ret.add(new WithParam(name, expr));
+ }
+ else
+ ret.add(new WithParam(name, content));
+ }
+ node = node.getNextSibling();
+ }
+ return ret;
+ }
+
+ /**
+ * Created element nodes have a copy of the namespace nodes in the
+ * stylesheet, except the XSLT namespace, extension namespaces, and
+ * exclude-result-prefixes.
+ */
+ final void addNamespaceNodes(Node source, Node target, Document doc,
+ Collection<String> elementExcludeResultPrefixes)
+ {
+ NamedNodeMap attrs = source.getAttributes();
+ if (attrs != null)
+ {
+ int len = attrs.getLength();
+ for (int i = 0; i < len; i++)
+ {
+ Node attr = attrs.item(i);
+ String uri = attr.getNamespaceURI();
+ if (uri == XMLConstants.XMLNS_ATTRIBUTE_NS_URI)
+ {
+ String prefix = attr.getLocalName();
+ if (XMLConstants.XMLNS_ATTRIBUTE.equals(prefix))
+ prefix = "#default";
+ String ns = attr.getNodeValue();
+ // Should the namespace be excluded?
+ if (XSL_NS.equals(ns) ||
+ extensionElementPrefixes.contains(prefix) ||
+ elementExcludeResultPrefixes.contains(prefix) ||
+ excludeResultPrefixes.contains(prefix))
+ continue;
+ // Is the namespace already defined on the target?
+ if (prefix == "#default")
+ prefix = null;
+ if (target.lookupNamespaceURI(prefix) != null)
+ continue;
+ attr = attr.cloneNode(true);
+ attr = doc.adoptNode(attr);
+ target.getAttributes().setNamedItemNS(attr);
+ }
+ }
+ }
+ Node parent = source.getParentNode();
+ if (parent != null)
+ addNamespaceNodes(parent, target, doc, elementExcludeResultPrefixes);
+ }
+
+ static final String getAttribute(NamedNodeMap attrs, String name)
+ {
+ Node attr = attrs.getNamedItem(name);
+ if (attr == null)
+ return null;
+ String ret = attr.getNodeValue();
+ if (ret.length() == 0)
+ return null;
+ return ret;
+ }
+
+ static final String getRequiredAttribute(NamedNodeMap attrs, String name,
+ Node source)
+ throws TransformerConfigurationException
+ {
+ String value = getAttribute(attrs, name);
+ if (value == null || value.length() == 0)
+ {
+ String msg =
+ name + " attribute is required on " + source.getNodeName();
+ DOMSourceLocator l = new DOMSourceLocator(source);
+ throw new TransformerConfigurationException(msg, l);
+ }
+ return value;
+ }
+
+ // Handle user data changes when nodes are cloned etc
+
+ public void handle(short op, String key, Object data, Node src, Node dst)
+ {
+ dst.setUserData(key, data, this);
+ }
+
+ public String toString()
+ {
+ CPStringBuilder b = new CPStringBuilder(getClass().getName());
+ b.append("[templates=");
+ b.append(templates);
+ b.append("]");
+ return b.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/SystemPropertyFunction.java b/libjava/classpath/gnu/xml/transform/SystemPropertyFunction.java
new file mode 100644
index 000000000..f314227e6
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/SystemPropertyFunction.java
@@ -0,0 +1,140 @@
+/* SystemPropertyFunction.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.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 <code>system-property()</code>function.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class SystemPropertyFunction
+ extends Expr
+ implements XPathFunction, Function
+{
+
+ List args;
+
+ public Object evaluate(List args)
+ throws XPathFunctionException
+ {
+ String name = (String) args.get(0);
+ return systemProperty(QName.valueOf(name));
+ }
+
+ 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));
+ }
+ String name = _string(context, values.get(0));
+ return systemProperty(QName.valueOf(name));
+ }
+
+ Object systemProperty(QName name)
+ {
+ String localName = name.getLocalPart();
+ String prefix = name.getPrefix();
+ String uri = name.getNamespaceURI();
+ if (Stylesheet.XSL_NS.equals(uri) ||
+ "xsl".equals(prefix))
+ {
+ if ("version".equals(localName))
+ {
+ return new Double(1.0d);
+ }
+ else if ("vendor".equals(localName))
+ {
+ return "The Free Software Foundation";
+ }
+ else if ("vendor-url".equals(localName))
+ {
+ return "http://www.gnu.org/";
+ }
+ else
+ {
+ return "";
+ }
+ }
+ return System.getProperty(localName);
+ }
+
+ public Expr clone(Object context)
+ {
+ SystemPropertyFunction f = new SystemPropertyFunction();
+ 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/Template.java b/libjava/classpath/gnu/xml/transform/Template.java
new file mode 100644
index 000000000..09d1a997c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/Template.java
@@ -0,0 +1,263 @@
+/* Template.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.PrintStream;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Node;
+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.Test;
+
+/**
+ * A template in an XSL stylesheet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class Template
+ implements Comparable
+{
+
+ static final double DEFAULT_PRIORITY = 0.5d;
+
+ final Stylesheet stylesheet;
+ final QName name;
+ final Pattern match;
+ final TemplateNode node;
+ final double priority;
+ final int precedence;
+ final QName mode;
+ final boolean isAnyNode; // is the match simply "node()"?
+
+ Template(Stylesheet stylesheet,
+ QName name, Pattern match, TemplateNode node,
+ int precedence, String priorityAttr, QName mode)
+ {
+ this.stylesheet = stylesheet;
+ this.name = name;
+ this.match = match;
+ this.node = node;
+ this.precedence = precedence;
+ this.mode = mode;
+
+ double p = DEFAULT_PRIORITY;
+ boolean a = false;
+ if (priorityAttr != null)
+ p = Double.parseDouble(priorityAttr);
+ else
+ {
+ // adjust priority if necessary
+ // see XSLT section 5.5
+ if (match instanceof Selector)
+ {
+ Selector selector = (Selector) match;
+ Test[] tests = selector.getTests();
+ if (tests.length > 0)
+ {
+ Test test = tests[0];
+ if (test instanceof NameTest)
+ {
+ NameTest nameTest = (NameTest) test;
+ if (nameTest.matchesAny())
+ p = -0.25d;
+ else if (nameTest.matchesAnyLocalName())
+ p = -0.20d;
+ else
+ p = 0.0d;
+ }
+ else
+ {
+ NodeTypeTest nodeTypeTest = (NodeTypeTest) test;
+ if (nodeTypeTest.getNodeType() ==
+ Node.PROCESSING_INSTRUCTION_NODE &&
+ nodeTypeTest.getData() != null)
+ p = 0.0d;
+ else
+ p = -0.5d;
+ a = (nodeTypeTest.getNodeType() == 0);
+ }
+ // Add a small difference for predicates
+ if (tests.length > 1)
+ p += ((double) tests.length - 1) * 0.001;
+ }
+ }
+ }
+ this.priority = p;
+ this.isAnyNode = a;
+ }
+
+ private Template(Stylesheet stylesheet,
+ QName name, Pattern match, TemplateNode node,
+ int precedence, double priority, QName mode, boolean isAnyNode)
+ {
+ this.stylesheet = stylesheet;
+ this.name = name;
+ this.match = match;
+ this.node = node;
+ this.precedence = precedence;
+ this.priority = priority;
+ this.mode = mode;
+ this.isAnyNode = isAnyNode;
+ }
+
+ Template clone(Stylesheet stylesheet)
+ {
+ // FIXME by cloning we lose the imports() functionality, so
+ // apply-imports will be broken.
+ return new Template(stylesheet,
+ name,
+ (match == null) ? null :
+ (Pattern) match.clone(stylesheet),
+ (node == null) ? null : node.clone(stylesheet),
+ precedence,
+ priority,
+ mode,
+ isAnyNode);
+ }
+
+ public int compareTo(Object other)
+ {
+ if (other instanceof Template)
+ {
+ Template t = (Template) other;
+ int d = t.precedence - precedence;
+ if (d != 0)
+ return d;
+ double d2 = t.priority - priority;
+ if (d2 != 0.0d)
+ return (int) Math.round(d2 * 1000.0d);
+ }
+ return 0;
+ }
+
+ Test getNodeTest(Expr expr)
+ {
+ return null;
+ }
+
+ boolean matches(QName mode, Node node)
+ {
+ if ((mode == null && this.mode != null) ||
+ (mode != null && !mode.equals(this.mode)))
+ return false;
+ if (match == null)
+ return false;
+ if (isAnyNode && node.getNodeType() == Node.DOCUMENT_NODE)
+ return false; // don't match document node
+ return match.matches(node);
+ }
+
+ boolean matches(QName name)
+ {
+ return name.equals(this.name);
+ }
+
+ boolean imports(Template other)
+ {
+ for (Stylesheet ctx = other.stylesheet.parent;
+ ctx != null;
+ ctx = ctx.parent)
+ {
+ if (ctx == stylesheet)
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * @param stylesheet the stylesheet
+ * @param parent the parent of result nodes
+ * @param context the context node in the source document
+ * @param pos the context position
+ * @param len the context size
+ * @param nextSibling if non-null, add result nodes before this node
+ */
+ void apply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ if (stylesheet.debug)
+ System.err.println("...applying " + toString() + " to " + context);
+ if (node != null)
+ node.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+
+ public String toString()
+ {
+ CPStringBuilder buf = new CPStringBuilder(getClass().getName());
+ buf.append('[');
+ if (name != null)
+ {
+ buf.append("name=");
+ buf.append(name);
+ }
+ else if (match != null)
+ {
+ buf.append("match=");
+ buf.append(match);
+ }
+ if (mode != null)
+ {
+ buf.append(",mode=");
+ buf.append(mode);
+ }
+ buf.append(",node=");
+ buf.append(node);
+ buf.append(']');
+ return buf.toString();
+
+ //return (name != null) ? name.toString() : match.toString();
+ }
+
+ void list(PrintStream out)
+ {
+ out.println(toString());
+ if (node != null)
+ node.list(1, out, true);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/TemplateNode.java b/libjava/classpath/gnu/xml/transform/TemplateNode.java
new file mode 100644
index 000000000..d4c223e01
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/TemplateNode.java
@@ -0,0 +1,130 @@
+/* TemplateNode.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.io.PrintStream;
+import java.util.Comparator;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.DocumentOrderComparator;
+
+/**
+ * Wrapper for a source node in a template.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+abstract class TemplateNode
+{
+
+ static final Comparator<Node> documentOrderComparator =
+ new DocumentOrderComparator();
+
+ TemplateNode children;
+ TemplateNode next;
+
+ final void apply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException
+ {
+ if (stylesheet.terminated)
+ return;
+ if (Thread.currentThread().isInterrupted())
+ {
+ // Try to head off any infinite loops at the pass
+ return;
+ }
+ if (stylesheet.debug)
+ {
+ System.err.println("Applying " + toString());
+ System.err.println("\twith context=" + context + ", pos=" + pos +
+ ", len=" + len);
+ }
+ doApply(stylesheet, mode, context, pos, len, parent, nextSibling);
+ }
+
+ abstract void doApply(Stylesheet stylesheet, QName mode,
+ Node context, int pos, int len,
+ Node parent, Node nextSibling)
+ throws TransformerException;
+
+ abstract TemplateNode clone(Stylesheet stylesheet);
+
+ public boolean references(QName var)
+ {
+ if (children != null && children.references(var))
+ return true;
+ if (next != null && next.references(var))
+ return true;
+ return false;
+ }
+
+ /**
+ * Debugging
+ */
+ void list(int depth, PrintStream out, boolean listNext)
+ {
+ for (int i = 0; i < depth; i++)
+ out.print(" ");
+ out.println(toString());
+ if (children != null)
+ children.list(depth + 1, out, true);
+ if (listNext && next != null)
+ next.list(depth, out, listNext);
+ }
+
+ /**
+ * Indicates whether the template for which this template node is the
+ * first node specifies the given parameter.
+ */
+ boolean hasParam(QName name)
+ {
+ for (TemplateNode ctx = this; ctx != null; ctx = ctx.next)
+ {
+ if (ctx instanceof ParameterNode)
+ {
+ ParameterNode param = (ParameterNode) ctx;
+ if (param.type == Bindings.PARAM && param.name.equals(name))
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/TemplatesImpl.java b/libjava/classpath/gnu/xml/transform/TemplatesImpl.java
new file mode 100644
index 000000000..fc741bc81
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/TemplatesImpl.java
@@ -0,0 +1,95 @@
+/* TemplatesImpl.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.Properties;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+
+/**
+ * GNU precompiled stylesheet implementation.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class TemplatesImpl
+ implements Templates
+{
+
+ final TransformerFactoryImpl factory;
+ final Stylesheet stylesheet;
+ final Properties outputProperties;
+
+ TemplatesImpl(TransformerFactoryImpl factory, Stylesheet stylesheet)
+ {
+ this.factory = factory;
+ this.stylesheet = stylesheet;
+ outputProperties = new TransformerOutputProperties(stylesheet);
+ }
+
+ public Transformer newTransformer()
+ throws TransformerConfigurationException
+ {
+ Stylesheet stylesheet = (Stylesheet) this.stylesheet.clone();
+ TransformerImpl transformer =
+ new TransformerImpl(factory, stylesheet, outputProperties);
+ stylesheet.transformer = transformer;
+ return transformer;
+ }
+
+ public Properties getOutputProperties()
+ {
+ return (Properties) outputProperties.clone();
+ }
+
+ public String toString()
+ {
+ CPStringBuilder b = new CPStringBuilder(getClass().getName());
+ b.append("[factory=");
+ b.append(factory);
+ b.append(",stylesheet=");
+ b.append(stylesheet);
+ b.append(",outputProperties=");
+ b.append(outputProperties);
+ b.append("]");
+ return b.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/TextNode.java b/libjava/classpath/gnu/xml/transform/TextNode.java
new file mode 100644
index 000000000..8263ef5bc
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/TextNode.java
@@ -0,0 +1,121 @@
+/* TextNode.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.Text;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing the XSL <code>text</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class TextNode
+ extends TemplateNode
+{
+
+ final boolean disableOutputEscaping;
+
+ TextNode(boolean disableOutputEscaping)
+ {
+ this.disableOutputEscaping = disableOutputEscaping;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new TextNode(disableOutputEscaping);
+ 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);
+ }
+ Text text = doc.createTextNode(value);
+ if (disableOutputEscaping)
+ text.setUserData("disable-output-escaping", "yes", stylesheet);
+ // Insert into result tree
+ if (nextSibling != null)
+ parent.insertBefore(text, nextSibling);
+ else
+ parent.appendChild(text);
+ if (next != null)
+ next.apply(stylesheet, mode,
+ context, pos, len,
+ parent, nextSibling);
+ }
+
+ public String toString()
+ {
+ CPStringBuilder buf = new CPStringBuilder("text");
+ if (disableOutputEscaping)
+ {
+ buf.append('[');
+ buf.append("disable-output-escaping");
+ buf.append(']');
+ }
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java b/libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java
new file mode 100644
index 000000000..972e8a282
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/TransformerFactoryImpl.java
@@ -0,0 +1,438 @@
+/* TransformerFactoryImpl.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.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URL;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+import java.util.Properties;
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.Source;
+import javax.xml.transform.Templates;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerConfigurationException;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.dom.DOMResult;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXResult;
+import javax.xml.transform.sax.SAXSource;
+import javax.xml.transform.sax.SAXTransformerFactory;
+import javax.xml.transform.sax.TemplatesHandler;
+import javax.xml.transform.sax.TransformerHandler;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.xpath.XPathFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.xml.sax.XMLFilter;
+import gnu.xml.dom.DomDocument;
+
+/**
+ * GNU transformer factory implementation.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class TransformerFactoryImpl
+ extends SAXTransformerFactory
+{
+
+ final XPathFactory xpathFactory;
+ final XSLURIResolver resolver;
+ ErrorListener userListener;
+ URIResolver userResolver;
+
+ public TransformerFactoryImpl()
+ {
+ xpathFactory = new gnu.xml.xpath.XPathFactoryImpl();
+ resolver = new XSLURIResolver();
+ }
+
+ public Transformer newTransformer(Source source)
+ throws TransformerConfigurationException
+ {
+ Stylesheet stylesheet = newStylesheet(source, 0, null);
+ Properties outputProperties =
+ new TransformerOutputProperties(stylesheet);
+ TransformerImpl transformer =
+ new TransformerImpl(this, stylesheet, outputProperties);
+ stylesheet.transformer = transformer;
+ return transformer;
+ }
+
+ public Transformer newTransformer()
+ throws TransformerConfigurationException
+ {
+ return new TransformerImpl(this, null, new Properties());
+ }
+
+ public Templates newTemplates(Source source)
+ throws TransformerConfigurationException
+ {
+ Stylesheet stylesheet = newStylesheet(source, 0, null);
+ return new TemplatesImpl(this, stylesheet);
+ }
+
+ Stylesheet newStylesheet(Source source, int precedence, Stylesheet parent)
+ throws TransformerConfigurationException
+ {
+ Document doc = null;
+ String systemId = null;
+ if (source != null)
+ {
+ try
+ {
+ DOMSource ds;
+ synchronized (resolver)
+ {
+ resolver.setUserResolver(userResolver);
+ resolver.setUserListener(userListener);
+ ds = resolver.resolveDOM(source, null, null);
+ }
+ Node node = ds.getNode();
+ if (node == null)
+ {
+ throw new TransformerConfigurationException("no source document");
+ }
+ doc = (node instanceof Document) ? (Document) node :
+ node.getOwnerDocument();
+ systemId = ds.getSystemId();
+ }
+ catch (TransformerException e)
+ {
+ throw new TransformerConfigurationException(e);
+ }
+ }
+ return new Stylesheet(this, parent, doc, systemId, precedence);
+ }
+
+ public Source getAssociatedStylesheet(Source source,
+ String media,
+ String title,
+ String charset)
+ throws TransformerConfigurationException
+ {
+ try
+ {
+ DOMSource ds;
+ synchronized (resolver)
+ {
+ resolver.setUserResolver(userResolver);
+ resolver.setUserListener(userListener);
+ ds = resolver.resolveDOM(source, null, null);
+ }
+ Node node = ds.getNode();
+ if (node == null)
+ {
+ throw new TransformerConfigurationException("no source document");
+ }
+ Document doc = (node instanceof Document) ? (Document) node :
+ node.getOwnerDocument();
+ LinkedList matches = new LinkedList();
+ for (node = doc.getFirstChild();
+ node != null;
+ node = node.getNextSibling())
+ {
+ if (node.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE &&
+ "xml-stylesheet".equals(node.getNodeName()))
+ {
+ Map params = parseParameters(node.getNodeValue());
+ if (media != null && !media.equals(params.get("media")))
+ {
+ continue;
+ }
+ if (title != null && !title.equals(params.get("title")))
+ {
+ continue;
+ }
+ if (charset != null && !charset.equals(params.get("charset")))
+ {
+ continue;
+ }
+ String href = (String) params.get("href");
+ URL url = resolver.resolveURL(null, node.getBaseURI(), href);
+ matches.add(url);
+ }
+ }
+ switch (matches.size())
+ {
+ case 0:
+ return null;
+ case 1:
+ return new StreamSource(((URL) matches.getFirst()).toString());
+ default:
+ // Create a source representing a stylesheet with a list of
+ // imports
+ DomDocument ssDoc = new DomDocument();
+ ssDoc.setBuilding(true);
+ // Create document element
+ Node root =
+ ssDoc.createElementNS(Stylesheet.XSL_NS, "stylesheet");
+ Node version =
+ ssDoc.createAttributeNS(null, "version");
+ version.setNodeValue("1.0");
+ root.getAttributes().setNamedItemNS(version);
+ ssDoc.appendChild(root);
+ // Create xsl:import for each URL
+ for (Iterator i = matches.iterator(); i.hasNext(); )
+ {
+ URL url = (URL) i.next();
+ Node imp =
+ ssDoc.createElementNS(Stylesheet.XSL_NS, "import");
+ Node href =
+ ssDoc.createAttributeNS(null, "href");
+ href.setNodeValue(url.toString());
+ imp.getAttributes().setNamedItemNS(href);
+ root.appendChild(imp);
+ }
+ ssDoc.setBuilding(false);
+ return new DOMSource(ssDoc);
+ }
+ }
+ catch (IOException e)
+ {
+ throw new TransformerConfigurationException(e);
+ }
+ catch (TransformerException e)
+ {
+ throw new TransformerConfigurationException(e);
+ }
+ }
+
+ Map parseParameters(String data)
+ {
+ Map ret = new LinkedHashMap();
+ int len = data.length();
+ String key = null;
+ int start = 0;
+ char quoteChar = '\u0000';
+ for (int i = 0; i < len; i++)
+ {
+ char c = data.charAt(i);
+ if (quoteChar == '\u0000' && c == ' ')
+ {
+ if (key == null && start < i)
+ {
+ key = data.substring(start, i);
+ }
+ else
+ {
+ String val = unquote(data.substring(start, i).trim());
+ ret.put(key, val);
+ key = null;
+ }
+ start = i + 1;
+ }
+ else if (c == '"')
+ {
+ quoteChar = (quoteChar == c) ? '\u0000' : c;
+ }
+ else if (c == '\'')
+ {
+ quoteChar = (quoteChar == c) ? '\u0000' : c;
+ }
+ }
+ if (start < len && key != null)
+ {
+ String val = unquote(data.substring(start, len).trim());
+ ret.put(key, val);
+ }
+ return ret;
+ }
+
+ String unquote(String text)
+ {
+ int end = text.length() - 1;
+ if (text.charAt(0) == '\'' && text.charAt(end) == '\'')
+ {
+ return text.substring(1, end);
+ }
+ if (text.charAt(0) == '"' && text.charAt(end) == '"')
+ {
+ return text.substring(1, end);
+ }
+ return text;
+ }
+
+ public void setURIResolver(URIResolver resolver)
+ {
+ userResolver = resolver;
+ }
+
+ public URIResolver getURIResolver()
+ {
+ return userResolver;
+ }
+
+ public void setFeature(String name, boolean value)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException("not supported");
+ }
+
+ public boolean getFeature(String name)
+ {
+ if (SAXSource.FEATURE.equals(name) ||
+ SAXResult.FEATURE.equals(name) ||
+ StreamSource.FEATURE.equals(name) ||
+ StreamResult.FEATURE.equals(name) ||
+ DOMSource.FEATURE.equals(name) ||
+ DOMResult.FEATURE.equals(name) ||
+ SAXTransformerFactory.FEATURE.equals(name))
+ {
+ return true;
+ }
+ return false;
+ }
+
+ public void setAttribute(String name, Object value)
+ throws IllegalArgumentException
+ {
+ throw new IllegalArgumentException("not supported");
+ }
+
+ public Object getAttribute(String name)
+ throws IllegalArgumentException
+ {
+ throw new IllegalArgumentException("not supported");
+ }
+
+ public void setErrorListener(ErrorListener listener)
+ throws IllegalArgumentException
+ {
+ userListener = listener;
+ }
+
+ public ErrorListener getErrorListener()
+ {
+ return userListener;
+ }
+
+ // -- SAXTransformerFactory --
+
+ public TemplatesHandler newTemplatesHandler()
+ throws TransformerConfigurationException
+ {
+ return new SAXTemplatesHandler(this);
+ }
+
+ public TransformerHandler newTransformerHandler()
+ throws TransformerConfigurationException
+ {
+ Transformer transformer = newTransformer();
+ return new SAXTransformerHandler(this, transformer);
+ }
+
+ public TransformerHandler newTransformerHandler(Source source)
+ throws TransformerConfigurationException
+ {
+ Transformer transformer = newTransformer(source);
+ return new SAXTransformerHandler(this, transformer);
+ }
+
+ public TransformerHandler newTransformerHandler(Templates templates)
+ throws TransformerConfigurationException
+ {
+ Transformer transformer = templates.newTransformer();
+ return new SAXTransformerHandler(this, transformer);
+ }
+
+ public XMLFilter newXMLFilter(Source source)
+ throws TransformerConfigurationException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public XMLFilter newXMLFilter(Templates templates)
+ throws TransformerConfigurationException
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ // -- SAXTransformerFactory end --
+
+ /**
+ * Syntax: TransformerFactoryImpl [<stylesheet> [<input> [<output>]]]
+ */
+ public static void main(String[] args)
+ throws Exception
+ {
+ InputStream stylesheet = null, in = null;
+ OutputStream out = null;
+ try
+ {
+ if (args.length > 0)
+ {
+ stylesheet = new FileInputStream(args[0]);
+ if (args.length > 1)
+ {
+ in = new FileInputStream(args[1]);
+ if (args.length > 2)
+ out = new FileOutputStream(args[2]);
+ }
+ }
+ if (in == null)
+ in = System.in;
+ if (out == null)
+ out = System.out;
+ TransformerFactory f = new TransformerFactoryImpl();
+ Transformer t = (stylesheet != null) ?
+ f.newTransformer(new StreamSource(stylesheet)) :
+ f.newTransformer();
+ t.transform(new StreamSource(in), new StreamResult(out));
+ }
+ finally
+ {
+ if (stylesheet != null)
+ stylesheet.close();
+ if (in != null && in instanceof FileInputStream)
+ in.close();
+ if (out != null && out instanceof FileOutputStream)
+ out.close();
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/TransformerImpl.java b/libjava/classpath/gnu/xml/transform/TransformerImpl.java
new file mode 100644
index 000000000..eb6a5dea1
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/TransformerImpl.java
@@ -0,0 +1,805 @@
+/* TransformerImpl.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.xml.transform;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.io.BufferedOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
+import java.net.MalformedURLException;
+import java.net.UnknownServiceException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import javax.xml.namespace.QName;
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+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.StreamResult;
+import org.w3c.dom.Document;
+import org.w3c.dom.DocumentType;
+import org.w3c.dom.DOMImplementation;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.LexicalHandler;
+import gnu.xml.dom.DomDoctype;
+import gnu.xml.dom.DomDocument;
+import gnu.xml.dom.ls.WriterOutputStream;
+
+/**
+ * The transformation process for a given stylesheet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class TransformerImpl
+ extends Transformer
+{
+
+ final TransformerFactoryImpl factory;
+ final Stylesheet stylesheet;
+ URIResolver uriResolver;
+ ErrorListener errorListener;
+ Properties outputProperties;
+
+ TransformerImpl(TransformerFactoryImpl factory,
+ Stylesheet stylesheet,
+ Properties outputProperties)
+ throws TransformerConfigurationException
+ {
+ this.factory = factory;
+ uriResolver = factory.userResolver;
+ errorListener = factory.userListener;
+ this.stylesheet = stylesheet;
+ this.outputProperties = outputProperties;
+ if (stylesheet != null)
+ {
+ // Set up parameter context for this transformer
+ stylesheet.bindings.push(Bindings.PARAM);
+ }
+ }
+
+ public void transform(Source xmlSource, Result outputTarget)
+ throws TransformerException
+ {
+ // Get the source tree
+ DOMSource source;
+ synchronized (factory.resolver)
+ {
+ factory.resolver.setUserResolver(uriResolver);
+ factory.resolver.setUserListener(errorListener);
+ source = factory.resolver.resolveDOM(xmlSource, null, null);
+ }
+ Node context = source.getNode();
+ Document doc = (context instanceof Document) ? (Document) context :
+ context.getOwnerDocument();
+ if (doc instanceof DomDocument)
+ {
+ // Suppress mutation events
+ ((DomDocument) doc).setBuilding(true);
+ }
+ // Get the result tree
+ Node parent = null, nextSibling = null;
+ if (outputTarget instanceof DOMResult)
+ {
+ DOMResult dr = (DOMResult) outputTarget;
+ parent = dr.getNode();
+ nextSibling = dr.getNextSibling();
+
+ Document rdoc = (parent instanceof Document) ? (Document) parent :
+ parent.getOwnerDocument();
+ if (rdoc instanceof DomDocument)
+ {
+ // Suppress mutation events and allow multiple root elements
+ DomDocument drdoc = (DomDocument) rdoc;
+ drdoc.setBuilding(true);
+ drdoc.setCheckWellformedness(false);
+ }
+ }
+ boolean created = false;
+ // Transformation
+ if (stylesheet != null)
+ {
+ if (parent == null)
+ {
+ // Create a new document to hold the result
+ DomDocument resultDoc = new DomDocument();
+ resultDoc.setBuilding(true);
+ resultDoc.setCheckWellformedness(false);
+ parent = resultDoc;
+ created = true;
+ }
+ // Make a copy of the source node, and strip it
+ context = context.cloneNode(true);
+ strip(stylesheet, context);
+ // XSLT transformation
+ try
+ {
+ // Set output properties in the underlying stylesheet
+ ((TransformerOutputProperties) outputProperties).apply();
+ stylesheet.initTopLevelVariables(context);
+ TemplateNode t = stylesheet.getTemplate(null, context, false);
+ if (t != null)
+ {
+ stylesheet.current = context;
+ t.apply(stylesheet, null, context, 1, 1, parent, nextSibling);
+ }
+ }
+ catch (TransformerException e)
+ {
+ // Done transforming, reset document
+ if (doc instanceof DomDocument)
+ ((DomDocument) doc).setBuilding(false);
+ throw e;
+ }
+ }
+ else
+ {
+ // Identity transform
+ Node clone = context.cloneNode(true);
+ if (context.getNodeType() != Node.DOCUMENT_NODE)
+ {
+ Document resultDoc;
+ if (parent == null)
+ {
+ // Create a new document to hold the result
+ DomDocument rd = new DomDocument();
+ rd.setBuilding(true);
+ rd.setCheckWellformedness(false);
+ parent = resultDoc = rd;
+ created = true;
+ }
+ else
+ {
+ resultDoc = (parent instanceof Document) ?
+ (Document) parent :
+ parent.getOwnerDocument();
+ }
+ Document sourceDoc = context.getOwnerDocument();
+ if (sourceDoc != resultDoc)
+ clone = resultDoc.adoptNode(clone);
+ if (nextSibling != null)
+ parent.insertBefore(clone, nextSibling);
+ else
+ parent.appendChild(clone);
+ }
+ else
+ {
+ // Cannot append document to another tree
+ parent = clone;
+ created = true;
+ }
+ }
+ String method = outputProperties.getProperty(OutputKeys.METHOD);
+ int outputMethod = "html".equals(method) ? Stylesheet.OUTPUT_HTML :
+ "text".equals(method) ? Stylesheet.OUTPUT_TEXT :
+ Stylesheet.OUTPUT_XML;
+ String encoding = outputProperties.getProperty(OutputKeys.ENCODING);
+ String publicId = outputProperties.getProperty(OutputKeys.DOCTYPE_PUBLIC);
+ String systemId = outputProperties.getProperty(OutputKeys.DOCTYPE_SYSTEM);
+ String version = outputProperties.getProperty(OutputKeys.VERSION);
+ boolean omitXmlDeclaration =
+ "yes".equals(outputProperties.getProperty(OutputKeys.OMIT_XML_DECLARATION));
+ boolean standalone =
+ "yes".equals(outputProperties.getProperty(OutputKeys.STANDALONE));
+ String mediaType = outputProperties.getProperty(OutputKeys.MEDIA_TYPE);
+ String cdataSectionElements =
+ outputProperties.getProperty(OutputKeys.CDATA_SECTION_ELEMENTS);
+ boolean indent =
+ "yes".equals(outputProperties.getProperty(OutputKeys.INDENT));
+ if (created && parent instanceof DomDocument)
+ {
+ // Discover document element
+ DomDocument resultDoc = (DomDocument) parent;
+ Node root = resultDoc.getDocumentElement();
+ // Add doctype if specified
+ if (publicId != null || systemId != null)
+ {
+ if (root != null)
+ {
+ // We must know the name of the root element to
+ // create the document type
+ DocumentType doctype = new DomDoctype(resultDoc,
+ root.getNodeName(),
+ publicId,
+ systemId);
+ resultDoc.insertBefore(doctype, root);
+ }
+ }
+ resultDoc.setBuilding(false);
+ resultDoc.setCheckWellformedness(true);
+ }
+ else if (publicId != null || systemId != null)
+ {
+ switch (parent.getNodeType())
+ {
+ case Node.DOCUMENT_NODE:
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ Document resultDoc = (parent instanceof Document) ?
+ (Document) parent :
+ parent.getOwnerDocument();
+ DOMImplementation impl = resultDoc.getImplementation();
+ Node root = resultDoc.getDocumentElement();
+ if (root != null)
+ {
+ DocumentType doctype =
+ impl.createDocumentType(root.getNodeName(),
+ publicId,
+ systemId);
+ resultDoc.insertBefore(doctype, root);
+ }
+ }
+ }
+ if (version != null)
+ parent.setUserData("version", version, stylesheet);
+ if (omitXmlDeclaration)
+ parent.setUserData("omit-xml-declaration", "yes", stylesheet);
+ if (standalone)
+ parent.setUserData("standalone", "yes", stylesheet);
+ if (mediaType != null)
+ parent.setUserData("media-type", mediaType, stylesheet);
+ if (cdataSectionElements != null)
+ {
+ List list = new LinkedList();
+ StringTokenizer st = new StringTokenizer(cdataSectionElements);
+ while (st.hasMoreTokens())
+ {
+ String name = st.nextToken();
+ String localName = name;
+ String uri = null;
+ String prefix = null;
+ int ci = name.indexOf(':');
+ if (ci != -1)
+ {
+ // Use namespaces defined on xsl:output node to resolve
+ // namespaces for QName
+ prefix = name.substring(0, ci);
+ localName = name.substring(ci + 1);
+ uri = stylesheet.output.lookupNamespaceURI(prefix);
+ }
+ list.add(new QName(uri, localName, prefix));
+ }
+ if (!list.isEmpty())
+ {
+ Document resultDoc = (parent instanceof Document) ?
+ (Document) parent :
+ parent.getOwnerDocument();
+ convertCdataSectionElements(resultDoc, parent, list);
+ }
+ }
+ if (indent)
+ {
+ if (created && parent instanceof DomDocument)
+ {
+ DomDocument domDoc = (DomDocument) parent;
+ domDoc.setBuilding(true);
+ domDoc.setCheckWellformedness(false);
+ }
+ parent.normalize();
+ if (stylesheet != null)
+ strip(stylesheet, parent);
+ Document resultDoc = (parent instanceof Document) ?
+ (Document) parent :
+ parent.getOwnerDocument();
+ reindent(resultDoc, parent, 0);
+ if (created && parent instanceof DomDocument)
+ {
+ DomDocument domDoc = (DomDocument) parent;
+ domDoc.setBuilding(false);
+ domDoc.setCheckWellformedness(true);
+ }
+ }
+ // Render result to the target device
+ if (outputTarget instanceof DOMResult)
+ {
+ if (created)
+ {
+ DOMResult dr = (DOMResult) outputTarget;
+ dr.setNode(parent);
+ dr.setNextSibling(null);
+ }
+ }
+ else if (outputTarget instanceof StreamResult)
+ {
+ StreamResult sr = (StreamResult) outputTarget;
+ IOException ex = null;
+ try
+ {
+ writeStreamResult(parent, sr, outputMethod, encoding);
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ try
+ {
+ writeStreamResult(parent, sr, outputMethod, "UTF-8");
+ }
+ catch (IOException e2)
+ {
+ ex = e2;
+ }
+ }
+ catch (IOException e)
+ {
+ ex = e;
+ }
+ if (ex != null)
+ {
+ if (errorListener != null)
+ errorListener.error(new TransformerException(ex));
+ else
+ ex.printStackTrace(System.err);
+ }
+ }
+ else if (outputTarget instanceof SAXResult)
+ {
+ SAXResult sr = (SAXResult) outputTarget;
+ try
+ {
+ ContentHandler ch = sr.getHandler();
+ LexicalHandler lh = sr.getLexicalHandler();
+ if (lh == null && ch instanceof LexicalHandler)
+ lh = (LexicalHandler) ch;
+ SAXSerializer serializer = new SAXSerializer();
+ serializer.serialize(parent, ch, lh);
+ }
+ catch (SAXException e)
+ {
+ if (errorListener != null)
+ errorListener.error(new TransformerException(e));
+ else
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+
+ /**
+ * Strip whitespace from the source tree.
+ */
+ static boolean strip(Stylesheet stylesheet, Node node)
+ throws TransformerConfigurationException
+ {
+ short nt = node.getNodeType();
+ if (nt == Node.ENTITY_REFERENCE_NODE)
+ {
+ // Replace entity reference with its content
+ Node parent = node.getParentNode();
+ Node nextSibling = node.getNextSibling();
+ Node child = node.getFirstChild();
+ while (child != null)
+ {
+ Node next = child.getNextSibling();
+ node.removeChild(child);
+ if (nextSibling != null)
+ parent.insertBefore(child, nextSibling);
+ else
+ parent.appendChild(child);
+ child = next;
+ }
+ return true;
+ }
+ if (nt == Node.TEXT_NODE || nt == Node.CDATA_SECTION_NODE)
+ {
+ // Denormalize text into whitespace and non-whitespace nodes
+ String text = node.getNodeValue();
+ String[] tokens = tokenizeWhitespace(text);
+ if (tokens.length > 1)
+ {
+ node.setNodeValue(tokens[0]);
+ Node parent = node.getParentNode();
+ Node nextSibling = node.getNextSibling();
+ Document doc = node.getOwnerDocument();
+ for (int i = 1; i < tokens.length; i++)
+ {
+ Node newChild = (nt == Node.CDATA_SECTION_NODE) ?
+ doc.createCDATASection(tokens[i]) :
+ doc.createTextNode(tokens[i]);
+ if (nextSibling != null)
+ parent.insertBefore(newChild, nextSibling);
+ else
+ parent.appendChild(newChild);
+ }
+ }
+ return !stylesheet.isPreserved((Text) node, true);
+ }
+ else
+ {
+ Node child = node.getFirstChild();
+ while (child != null)
+ {
+ boolean remove = strip(stylesheet, child);
+ Node next = child.getNextSibling();
+ if (remove)
+ node.removeChild(child);
+ child = next;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Tokenize the specified text into contiguous whitespace-only and
+ * non-whitespace chunks.
+ */
+ private static String[] tokenizeWhitespace(String text)
+ {
+ int len = text.length();
+ int start = 0, end = len - 1;
+ // Find index of text start
+ for (int i = 0; i < len; i++)
+ {
+ char c = text.charAt(i);
+ boolean whitespace = (c == ' ' || c == '\n' || c == '\t' || c == '\r');
+ if (whitespace)
+ start++;
+ else
+ break;
+ }
+ if (start == end) // all whitespace
+ return new String[] { text };
+ // Find index of text end
+ for (int i = end; i > start; i--)
+ {
+ char c = text.charAt(i);
+ boolean whitespace = (c == ' ' || c == '\n' || c == '\t' || c == '\r');
+ if (whitespace)
+ end--;
+ else
+ break;
+ }
+ if (start == 0 && end == len - 1) // all non-whitespace
+ return new String[] { text };
+ // whitespace, then text, then whitespace
+ String[] ret = (start > 0 && end < len - 1) ?
+ new String[3] : new String[2];
+ int i = 0;
+ if (start > 0)
+ ret[i++] = text.substring(0, start);
+ ret[i++] = text.substring(start, end + 1);
+ if (end < len - 1)
+ ret[i++] = text.substring(end + 1);
+ return ret;
+ }
+
+ /**
+ * Obtain a suitable output stream for writing the result to,
+ * and use the StreamSerializer to write the result tree to the stream.
+ */
+ void writeStreamResult(Node node, StreamResult sr, int outputMethod,
+ String encoding)
+ throws IOException
+ {
+ OutputStream out = null;
+ boolean created = false;
+ try
+ {
+ out = sr.getOutputStream();
+ if (out == null)
+ {
+ Writer writer = sr.getWriter();
+ if (writer != null)
+ out = new WriterOutputStream(writer);
+ }
+ if (out == null)
+ {
+ String systemId = sr.getSystemId();
+ try
+ {
+ URL url = new URL(systemId);
+ URLConnection connection = url.openConnection();
+ // We need to call setDoInput(false), because our
+ // implementation of the file protocol allows writing
+ // (unlike Sun), but it will fail with a FileNotFoundException
+ // if we also open the connection for input and the output
+ // file doesn't yet exist.
+ connection.setDoInput(false);
+ connection.setDoOutput(true);
+ out = connection.getOutputStream();
+ }
+ catch (MalformedURLException e)
+ {
+ out = new FileOutputStream(systemId);
+ }
+ catch (UnknownServiceException e)
+ {
+ URL url = new URL(systemId);
+ out = new FileOutputStream(url.getPath());
+ }
+ created = true;
+ }
+ out = new BufferedOutputStream(out);
+ StreamSerializer serializer =
+ new StreamSerializer(outputMethod, encoding, null);
+ if (stylesheet != null)
+ {
+ Collection celem = stylesheet.outputCdataSectionElements;
+ serializer.setCdataSectionElements(celem);
+ }
+ serializer.serialize(node, out);
+ out.flush();
+ }
+ finally
+ {
+ try
+ {
+ if (out != null && created)
+ out.close();
+ }
+ catch (IOException e)
+ {
+ if (errorListener != null)
+ {
+ try
+ {
+ errorListener.error(new TransformerException(e));
+ }
+ catch (TransformerException e2)
+ {
+ e2.printStackTrace(System.err);
+ }
+ }
+ else
+ e.printStackTrace(System.err);
+ }
+ }
+ }
+
+ void copyChildren(Document dstDoc, Node src, Node dst)
+ {
+ Node srcChild = src.getFirstChild();
+ while (srcChild != null)
+ {
+ Node dstChild = dstDoc.adoptNode(srcChild);
+ dst.appendChild(dstChild);
+ srcChild = srcChild.getNextSibling();
+ }
+ }
+
+ public void setParameter(String name, Object value)
+ {
+ if (stylesheet != null)
+ stylesheet.bindings.set(new QName(null, name), value, Bindings.PARAM);
+ }
+
+ public Object getParameter(String name)
+ {
+ if (stylesheet != null)
+ return stylesheet.bindings.get(new QName(null, name), null, 1, 1);
+ return null;
+ }
+
+ public void clearParameters()
+ {
+ if (stylesheet != null)
+ {
+ stylesheet.bindings.pop(Bindings.PARAM);
+ stylesheet.bindings.push(Bindings.PARAM);
+ }
+ }
+
+ public void setURIResolver(URIResolver resolver)
+ {
+ uriResolver = resolver;
+ }
+
+ public URIResolver getURIResolver()
+ {
+ return uriResolver;
+ }
+
+ public void setOutputProperties(Properties oformat)
+ throws IllegalArgumentException
+ {
+ if (oformat == null)
+ outputProperties.clear();
+ else
+ outputProperties.putAll(oformat);
+ }
+
+ public Properties getOutputProperties()
+ {
+ return (Properties) outputProperties.clone();
+ }
+
+ public void setOutputProperty(String name, String value)
+ throws IllegalArgumentException
+ {
+ outputProperties.put(name, value);
+ }
+
+ public String getOutputProperty(String name)
+ throws IllegalArgumentException
+ {
+ return outputProperties.getProperty(name);
+ }
+
+ public void setErrorListener(ErrorListener listener)
+ {
+ errorListener = listener;
+ }
+
+ public ErrorListener getErrorListener()
+ {
+ return errorListener;
+ }
+
+ static final String INDENT_WHITESPACE = " ";
+
+ /*
+ * Apply indent formatting to the given tree.
+ */
+ void reindent(Document doc, Node node, int offset)
+ {
+ if (node.hasChildNodes())
+ {
+ boolean markupContent = false;
+ boolean textContent = false;
+ List children = new LinkedList();
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ switch (ctx.getNodeType())
+ {
+ case Node.ELEMENT_NODE:
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ case Node.DOCUMENT_TYPE_NODE:
+ markupContent = true;
+ break;
+ case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ case Node.ENTITY_REFERENCE_NODE:
+ case Node.COMMENT_NODE:
+ textContent = true;
+ break;
+ }
+ children.add(ctx);
+ ctx = ctx.getNextSibling();
+ }
+ if (markupContent)
+ {
+ if (textContent)
+ {
+ // XXX handle mixed content differently?
+ }
+ int nodeType = node.getNodeType();
+ if (nodeType == Node.DOCUMENT_NODE)
+ {
+ for (Iterator i = children.iterator(); i.hasNext(); )
+ {
+ ctx = (Node) i.next();
+ reindent(doc, ctx, offset);
+ }
+ }
+ else
+ {
+ CPStringBuilder buf = new CPStringBuilder();
+ buf.append('\n');
+ for (int i = 0; i < offset + 1; i++)
+ buf.append(INDENT_WHITESPACE);
+ String ws = buf.toString();
+ for (Iterator i = children.iterator(); i.hasNext(); )
+ {
+ ctx = (Node) i.next();
+ node.insertBefore(doc.createTextNode(ws), ctx);
+ reindent(doc, ctx, offset + 1);
+ }
+ buf = new CPStringBuilder();
+ buf.append('\n');
+ for (int i = 0; i < offset; i++)
+ buf.append(INDENT_WHITESPACE);
+ ws = buf.toString();
+ node.appendChild(doc.createTextNode(ws));
+ }
+ }
+ }
+ }
+
+ /**
+ * Converts the text node children of any cdata-section-elements in the
+ * tree to CDATA section nodes.
+ */
+ void convertCdataSectionElements(Document doc, Node node, List list)
+ {
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ boolean match = false;
+ for (Iterator i = list.iterator(); i.hasNext(); )
+ {
+ QName qname = (QName) i.next();
+ if (match(qname, node))
+ {
+ match = true;
+ break;
+ }
+ }
+ if (match)
+ {
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ if (ctx.getNodeType() == Node.TEXT_NODE)
+ {
+ Node cdata = doc.createCDATASection(ctx.getNodeValue());
+ node.replaceChild(cdata, ctx);
+ ctx = cdata;
+ }
+ ctx = ctx.getNextSibling();
+ }
+ }
+ }
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ if (ctx.hasChildNodes())
+ convertCdataSectionElements(doc, ctx, list);
+ ctx = ctx.getNextSibling();
+ }
+ }
+
+ boolean match(QName qname, Node node)
+ {
+ String ln1 = qname.getLocalPart();
+ String ln2 = node.getLocalName();
+ if (ln2 == null)
+ return ln1.equals(node.getNodeName());
+ else
+ {
+ String uri1 = qname.getNamespaceURI();
+ String uri2 = node.getNamespaceURI();
+ return (uri1.equals(uri2) && ln1.equals(ln2));
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/TransformerOutputProperties.java b/libjava/classpath/gnu/xml/transform/TransformerOutputProperties.java
new file mode 100644
index 000000000..ddaa260c4
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/TransformerOutputProperties.java
@@ -0,0 +1,186 @@
+/* TransformerOutputProperties.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.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import javax.xml.transform.OutputKeys;
+
+/**
+ * Helper class to manage JAXP user setting of output properties.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class TransformerOutputProperties
+ extends Properties
+{
+
+ final Properties defaultProperties;
+ final Stylesheet stylesheet;
+ boolean dirty;
+
+ TransformerOutputProperties(Stylesheet stylesheet)
+ {
+ this.stylesheet = stylesheet;
+ defaultProperties = new Properties();
+ switch (stylesheet.outputMethod)
+ {
+ case Stylesheet.OUTPUT_XML:
+ defaultProperties.put(OutputKeys.METHOD, "xml");
+ break;
+ case Stylesheet.OUTPUT_HTML:
+ defaultProperties.put(OutputKeys.METHOD, "html");
+ break;
+ case Stylesheet.OUTPUT_TEXT:
+ defaultProperties.put(OutputKeys.METHOD, "text");
+ break;
+ }
+ if (stylesheet.outputVersion != null)
+ {
+ defaultProperties.put(OutputKeys.VERSION, stylesheet.outputVersion);
+ }
+ if (stylesheet.outputEncoding != null)
+ {
+ defaultProperties.put(OutputKeys.ENCODING, stylesheet.outputEncoding);
+ }
+ defaultProperties.put(OutputKeys.OMIT_XML_DECLARATION,
+ stylesheet.outputOmitXmlDeclaration ? "yes" : "no");
+ defaultProperties.put(OutputKeys.STANDALONE,
+ stylesheet.outputStandalone ? "yes" : "no");
+ if (stylesheet.outputPublicId != null)
+ {
+ defaultProperties.put(OutputKeys.DOCTYPE_PUBLIC,
+ stylesheet.outputPublicId);
+ }
+ if (stylesheet.outputSystemId != null)
+ {
+ defaultProperties.put(OutputKeys.DOCTYPE_SYSTEM,
+ stylesheet.outputSystemId);
+ }
+ CPStringBuilder buf = new CPStringBuilder();
+ for (Iterator i = stylesheet.outputCdataSectionElements.iterator();
+ i.hasNext(); )
+ {
+ if (buf.length() > 0)
+ {
+ buf.append(' ');
+ }
+ buf.append((String) i.next());
+ }
+ defaultProperties.put(OutputKeys.CDATA_SECTION_ELEMENTS, buf.toString());
+ defaultProperties.put(OutputKeys.INDENT,
+ stylesheet.outputIndent ? "yes" : "no");
+ if (stylesheet.outputMediaType != null)
+ {
+ defaultProperties.put(OutputKeys.MEDIA_TYPE,
+ stylesheet.outputMediaType);
+ }
+ }
+
+ public String getProperty(String key)
+ {
+ String val = super.getProperty(key);
+ if (val == null)
+ {
+ val = defaultProperties.getProperty(key);
+ }
+ return val;
+ }
+
+ public Object put(Object key, Object value)
+ {
+ Object ret = super.put(key, value);
+ dirty = true;
+ return ret;
+ }
+
+ public void clear()
+ {
+ super.clear();
+ dirty = true;
+ }
+
+ /**
+ * Applies the current set of properties to the underlying stylesheet.
+ */
+ void apply()
+ {
+ if (!dirty)
+ {
+ return;
+ }
+ String method = getProperty(OutputKeys.METHOD);
+ if ("xml".equals(method))
+ {
+ stylesheet.outputMethod = Stylesheet.OUTPUT_XML;
+ }
+ else if ("html".equals(method))
+ {
+ stylesheet.outputMethod = Stylesheet.OUTPUT_HTML;
+ }
+ else if ("text".equals(method))
+ {
+ stylesheet.outputMethod = Stylesheet.OUTPUT_TEXT;
+ }
+ stylesheet.outputVersion = getProperty(OutputKeys.VERSION);
+ stylesheet.outputEncoding = getProperty(OutputKeys.ENCODING);
+ stylesheet.outputOmitXmlDeclaration =
+ "yes".equals(getProperty(OutputKeys.OMIT_XML_DECLARATION));
+ stylesheet.outputStandalone =
+ "yes".equals(getProperty(OutputKeys.STANDALONE));
+ stylesheet.outputPublicId = getProperty(OutputKeys.DOCTYPE_PUBLIC);
+ stylesheet.outputSystemId = getProperty(OutputKeys.DOCTYPE_SYSTEM);
+ StringTokenizer st =
+ new StringTokenizer(getProperty(OutputKeys.CDATA_SECTION_ELEMENTS));
+ Collection acc = new LinkedHashSet();
+ while (st.hasMoreTokens())
+ {
+ acc.add(st.nextToken());
+ }
+ stylesheet.outputCdataSectionElements = acc;
+ stylesheet.outputIndent = "yes".equals(getProperty(OutputKeys.INDENT));
+ stylesheet.outputMediaType = getProperty(OutputKeys.MEDIA_TYPE);
+ dirty = false;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/URIResolverEntityResolver.java b/libjava/classpath/gnu/xml/transform/URIResolverEntityResolver.java
new file mode 100644
index 000000000..49193a473
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/URIResolverEntityResolver.java
@@ -0,0 +1,83 @@
+/* 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.transform;
+
+import java.io.IOException;
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.sax.SAXSource;
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * EntityResolver that wraps a URIResolver.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class URIResolverEntityResolver
+ implements EntityResolver
+{
+
+ final URIResolver resolver;
+
+ URIResolverEntityResolver(URIResolver resolver)
+ {
+ this.resolver = resolver;
+ }
+
+ public InputSource resolveEntity(String publicId, String systemId)
+ throws SAXException, IOException
+ {
+ try
+ {
+ Source source = resolver.resolve(null, systemId);
+ if (source == null)
+ {
+ return null;
+ }
+ return SAXSource.sourceToInputSource(source);
+ }
+ catch (TransformerException e)
+ {
+ throw new SAXException(e);
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/UnparsedEntityUriFunction.java b/libjava/classpath/gnu/xml/transform/UnparsedEntityUriFunction.java
new file mode 100644
index 000000000..5eae78cb2
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/UnparsedEntityUriFunction.java
@@ -0,0 +1,132 @@
+/* UnparsedEntityUriFunction.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.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.DocumentType;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.w3c.dom.Notation;
+import gnu.xml.xpath.Expr;
+import gnu.xml.xpath.Function;
+
+/**
+ * The XSLT <code>unparsed-entity-uri()</code>function.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class UnparsedEntityUriFunction
+ extends Expr
+ implements XPathFunction, Function
+{
+
+ List<Expr> args;
+
+ public Object evaluate(List args)
+ throws XPathFunctionException
+ {
+ // Useless...
+ return Collections.emptySet();
+ }
+
+ public void setArguments(List<Expr> args)
+ {
+ this.args = args;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ int arity = args.size();
+ List<Object> values = new ArrayList<Object>(arity);
+ for (int i = 0; i < arity; i++)
+ {
+ Expr arg = args.get(i);
+ values.add(arg.evaluate(context, pos, len));
+ }
+ String name = _string(context, values.get(0));
+ DocumentType doctype = context.getOwnerDocument().getDoctype();
+ if (doctype != null)
+ {
+ NamedNodeMap notations = doctype.getNotations();
+ Notation notation = (Notation) notations.getNamedItem(name);
+ if (notation != null)
+ {
+ String systemId = notation.getSystemId();
+ // XXX absolutize?
+ if (systemId != null)
+ {
+ return systemId;
+ }
+ }
+ }
+ return "";
+ }
+
+ public Expr clone(Object context)
+ {
+ UnparsedEntityUriFunction f = new UnparsedEntityUriFunction();
+ int len = args.size();
+ List<Expr> args2 = new ArrayList<Expr>(len);
+ for (int i = 0; i < len; i++)
+ {
+ args2.add(args.get(i).clone(context));
+ }
+ f.setArguments(args2);
+ return f;
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator<Expr> i = args.iterator(); i.hasNext(); )
+ {
+ if (i.next().references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/ValueOfNode.java b/libjava/classpath/gnu/xml/transform/ValueOfNode.java
new file mode 100644
index 000000000..0d9a656e7
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/ValueOfNode.java
@@ -0,0 +1,141 @@
+/* ValueOfNode.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.Iterator;
+import javax.xml.namespace.QName;
+import javax.xml.transform.TransformerException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.Text;
+import gnu.xml.xpath.Expr;
+
+/**
+ * A template node representing an XSLT <code>value-of</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class ValueOfNode
+ extends TemplateNode
+{
+
+ final Expr select;
+ final boolean disableOutputEscaping;
+
+ ValueOfNode(Expr select, boolean disableOutputEscaping)
+ {
+ this.select = select;
+ this.disableOutputEscaping = disableOutputEscaping;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new ValueOfNode(select.clone(stylesheet),
+ disableOutputEscaping);
+ 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
+ {
+ Object ret = select.evaluate(context, pos, len);
+ String value;
+ if (ret instanceof Collection)
+ {
+ CPStringBuilder buf = new CPStringBuilder();
+ for (Node node : ((Collection<Node>) ret))
+ {
+ buf.append(Expr.stringValue(node));
+ }
+ value = buf.toString();
+ }
+ else if (ret == null)
+ value = "";
+ else
+ value = Expr._string(context, ret);
+ if (stylesheet.debug)
+ System.err.println("value-of: "+context+" "+ select + " -> "+ value);
+ if (value != null && value.length() > 0)
+ {
+ Document doc = (parent instanceof Document) ?
+ (Document) parent : parent.getOwnerDocument();
+ Text textNode = doc.createTextNode(value);
+ if (disableOutputEscaping)
+ textNode.setUserData("disable-output-escaping", "yes", stylesheet);
+ if (nextSibling != null)
+ parent.insertBefore(textNode, nextSibling);
+ else
+ parent.appendChild(textNode);
+ }
+ // value-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("value-of");
+ buf.append('[');
+ buf.append("select=");
+ buf.append(select);
+ if (disableOutputEscaping)
+ buf.append(",disableOutputEscaping");
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/WhenNode.java b/libjava/classpath/gnu/xml/transform/WhenNode.java
new file mode 100644
index 000000000..abfe796fd
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/WhenNode.java
@@ -0,0 +1,115 @@
+/* WhenNode.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 <code>when</code> instruction.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class WhenNode
+ extends TemplateNode
+{
+
+ final Expr test;
+
+ WhenNode(Expr test)
+ {
+ this.test = test;
+ }
+
+ TemplateNode clone(Stylesheet stylesheet)
+ {
+ TemplateNode ret = new WhenNode(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);
+ }
+ else
+ {
+ 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("when");
+ buf.append('[');
+ buf.append("test=");
+ buf.append(test);
+ buf.append(']');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/WithParam.java b/libjava/classpath/gnu/xml/transform/WithParam.java
new file mode 100644
index 000000000..2e726fb82
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/WithParam.java
@@ -0,0 +1,127 @@
+/* WithParam.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 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 specification for setting a variable or parameter during template
+ * processing with <code>apply-templates</code> or
+ * <code>call-template</code>.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class WithParam
+{
+
+ final QName name;
+ final Expr select;
+ final TemplateNode content;
+
+ WithParam(QName name, Expr select)
+ {
+ this.name = name;
+ this.select = select;
+ content = null;
+ }
+
+ WithParam(QName name, TemplateNode content)
+ {
+ this.name = name;
+ this.content = content;
+ select = null;
+ }
+
+ 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 (content == null)
+ {
+ return "";
+ }
+ else
+ {
+ Document doc = (context instanceof Document) ? (Document) context :
+ context.getOwnerDocument();
+ DocumentFragment fragment = doc.createDocumentFragment();
+ content.apply(stylesheet, mode,
+ context, pos, len,
+ fragment, null);
+ return Collections.singleton(fragment);
+ }
+ }
+
+ WithParam clone(Stylesheet stylesheet)
+ {
+ if (content == null)
+ {
+ return new WithParam(name,
+ select.clone(stylesheet));
+ }
+ else
+ {
+ return new WithParam(name,
+ content.clone(stylesheet));
+ }
+ }
+
+ boolean references(QName var)
+ {
+ if (select != null && select.references(var))
+ {
+ return true;
+ }
+ if (content != null && content.references(var))
+ {
+ return true;
+ }
+ return false;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/XSLComparator.java b/libjava/classpath/gnu/xml/transform/XSLComparator.java
new file mode 100644
index 000000000..1fd0b20e6
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/XSLComparator.java
@@ -0,0 +1,118 @@
+/* XSLComparator.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.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.text.Collator;
+import org.w3c.dom.Node;
+import gnu.xml.xpath.Expr;
+
+/**
+ * Comparator for sorting lists of nodes according to a list of sort keys.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class XSLComparator
+ implements Comparator<Node>
+{
+
+ final List<SortKey> sortKeys;
+
+ XSLComparator(List<SortKey> sortKeys)
+ {
+ this.sortKeys = sortKeys;
+ }
+
+ public int compare(Node n1, Node n2)
+ {
+ for (SortKey sortKey : sortKeys)
+ {
+ String k1 = sortKey.key(n1);
+ String k2 = sortKey.key(n2);
+ if ("text".equals(sortKey.dataType))
+ {
+ Locale locale = (sortKey.lang == null) ? Locale.getDefault() :
+ new Locale(sortKey.lang);
+ Collator collator = Collator.getInstance(locale);
+ int d = collator.compare(k1, k2);
+ if (d != 0)
+ {
+ switch (sortKey.caseOrder)
+ {
+ case SortKey.UPPER_FIRST:
+ // TODO
+ break;
+ case SortKey.LOWER_FIRST:
+ // TODO
+ break;
+ }
+ if (sortKey.descending)
+ {
+ d = -d;
+ }
+ return d;
+ }
+ }
+ else if ("number".equals(sortKey.dataType))
+ {
+ double kn1 = Expr._number(n1, k1);
+ double kn2 = Expr._number(n2, k2);
+ int d;
+ if (Double.isNaN(kn1) || Double.isInfinite(kn2))
+ {
+ d = -1;
+ }
+ else if (Double.isNaN(kn2) || Double.isInfinite(kn1))
+ {
+ d = 1;
+ }
+ else
+ {
+ // conversion to int may give 0 for small numbers
+ d = (kn1 > kn2) ? 1 : (kn1 < kn2) ? -1 : 0;
+ }
+ return (sortKey.descending) ? -d : d;
+ }
+ }
+ return 0;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/XSLURIResolver.java b/libjava/classpath/gnu/xml/transform/XSLURIResolver.java
new file mode 100644
index 000000000..cf596c1e6
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/XSLURIResolver.java
@@ -0,0 +1,321 @@
+/* XSLURIResolver.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.io.File;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.Reader;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.HashMap;
+import java.util.Map;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.ErrorListener;
+import javax.xml.transform.Source;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.URIResolver;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.sax.SAXSource;
+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 gnu.xml.dom.DomDocument;
+import gnu.xml.dom.ls.SAXEventSink;
+import gnu.xml.dom.ls.ReaderInputStream;
+
+/**
+ * URI resolver for XSLT.
+ * This resolver parses external entities into DOMSources. It
+ * maintains a cache of URIs to DOMSources to avoid expensive re-parsing.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class XSLURIResolver
+ implements URIResolver
+{
+
+ final Map<String,Long> lastModifiedCache = new HashMap<String,Long>();
+ final Map<String,Node> nodeCache = new HashMap<String,Node>();
+ DocumentBuilder builder;
+ URIResolver userResolver;
+ ErrorListener userListener;
+
+ void setUserResolver(URIResolver userResolver)
+ {
+ this.userResolver = userResolver;
+ }
+
+ void setUserListener(ErrorListener userListener)
+ {
+ this.userListener = userListener;
+ }
+
+ /**
+ * Clear the cache.
+ */
+ void flush()
+ {
+ lastModifiedCache.clear();
+ nodeCache.clear();
+ }
+
+ public Source resolve(String href, String base)
+ throws TransformerException
+ {
+ Source source = null;
+ if (userResolver != null)
+ {
+ source = userResolver.resolve(base, href);
+ }
+ return resolveDOM(source, href, base);
+ }
+
+ DOMSource resolveDOM(Source source, String base, String href)
+ throws TransformerException
+ {
+ if (source != null && source instanceof DOMSource)
+ {
+ return (DOMSource) source;
+ }
+ String systemId = (source == null) ? null : source.getSystemId();
+ long lastModified = 0L, lastLastModified = 0L;
+
+ try
+ {
+ Node node = null;
+ InputStream in = null;
+ if (source != null && source instanceof StreamSource)
+ {
+ StreamSource ss = (StreamSource) source;
+ in = ss.getInputStream();
+ if (in == null)
+ {
+ Reader reader = ss.getReader();
+ if (reader != null)
+ {
+ in = new ReaderInputStream(reader);
+ }
+ }
+ }
+ else if (source != null && source instanceof SAXSource)
+ {
+ SAXSource ss = (SAXSource) source;
+ InputSource input = ss.getInputSource();
+ if (input != null)
+ {
+ if (systemId == null)
+ systemId = input.getSystemId();
+ XMLReader reader = ss.getXMLReader();
+ if (reader != null)
+ return parse(input, reader);
+ }
+ }
+ if (in == null)
+ {
+ URL url = resolveURL(systemId, base, href);
+ if (url != null)
+ {
+ systemId = url.toString();
+ node = nodeCache.get(systemId);
+ // Is the resource up to date?
+ URLConnection conn = url.openConnection();
+ Long llm = lastModifiedCache.get(systemId);
+ if (llm != null)
+ {
+ lastLastModified = llm.longValue();
+ conn.setIfModifiedSince(lastLastModified);
+ }
+ conn.connect();
+ lastModified = conn.getLastModified();
+ if (node != null &&
+ lastModified > 0L &&
+ lastModified <= lastLastModified)
+ {
+ // Resource unchanged
+ return new DOMSource(node, systemId);
+ }
+ else
+ {
+ // Resource new or modified
+ in = conn.getInputStream();
+ nodeCache.put(systemId, node);
+ lastModifiedCache.put(systemId, new Long(lastModified));
+ }
+ }
+ else
+ {
+ throw new TransformerException("can't resolve URL: " +
+ systemId);
+ }
+ }
+ InputSource input = new InputSource(in);
+ input.setSystemId(systemId);
+ DocumentBuilder builder = getDocumentBuilder();
+ node = builder.parse(input);
+ return new DOMSource(node, systemId);
+ }
+ catch (IOException e)
+ {
+ throw new TransformerException(e);
+ }
+ catch (SAXException e)
+ {
+ throw new TransformerException(e);
+ }
+ }
+
+ URL resolveURL(String systemId, String base, String href)
+ throws IOException
+ {
+ URL url = null;
+ try
+ {
+ if (systemId != null)
+ {
+ try
+ {
+ url = new URL(systemId);
+ }
+ catch (MalformedURLException e)
+ {
+ // Try building from base + href
+ }
+ }
+ if (url == null)
+ {
+ if (base != null)
+ {
+ URL baseURL = new URL(base);
+ url = new URL(baseURL, href);
+ }
+ else if (href != null)
+ {
+ url = new URL(href);
+ }
+ else
+ {
+ // See below
+ throw new MalformedURLException(systemId);
+ }
+ }
+ return url;
+ }
+ catch (MalformedURLException e)
+ {
+ // Fall back to local filesystem
+ File file = null;
+ if (href == null)
+ {
+ href = systemId;
+ }
+ if (base != null)
+ {
+ int lsi = base.lastIndexOf(File.separatorChar);
+ if (lsi != -1 && lsi < base.length() - 1)
+ {
+ base = base.substring(0, lsi);
+ }
+ File baseFile = new File(base);
+ file = new File(baseFile, href);
+ }
+ else if (href != null)
+ {
+ file = new File(href);
+ }
+ return (file == null) ? null : file.toURL();
+ }
+ }
+
+ DocumentBuilder getDocumentBuilder()
+ throws TransformerException
+ {
+ try
+ {
+ if (builder == null)
+ {
+ DocumentBuilderFactory factory =
+ DocumentBuilderFactory.newInstance();
+ factory.setNamespaceAware(true);
+ factory.setExpandEntityReferences(true);
+ builder = factory.newDocumentBuilder();
+ }
+ if (userResolver != null)
+ {
+ builder.setEntityResolver(new URIResolverEntityResolver(userResolver));
+ }
+ if (userListener != null)
+ {
+ builder.setErrorHandler(new ErrorListenerErrorHandler(userListener));
+ }
+ return builder;
+ }
+ catch (Exception e)
+ {
+ throw new TransformerException(e);
+ }
+ }
+
+ DOMSource parse(InputSource source, XMLReader reader)
+ throws SAXException, IOException
+ {
+ SAXEventSink eventSink = new SAXEventSink();
+ eventSink.setReader(reader);
+ eventSink.setNamespaceAware(true);
+ 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);
+ // XXX entityResolver
+ // XXX errorHandler
+ reader.parse(source);
+ Document doc = eventSink.getDocument();
+ String systemId = source.getSystemId();
+ if (systemId != null && doc instanceof DomDocument)
+ ((DomDocument) doc).setDocumentURI(systemId);
+ return new DOMSource(doc, systemId);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/transform/package.html b/libjava/classpath/gnu/xml/transform/package.html
new file mode 100644
index 000000000..d4355966c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/transform/package.html
@@ -0,0 +1,77 @@
+<html>
+<body>
+
+<h1>GNU JAXP XSL transformer</h1>
+
+<div>
+This package contains a Java XSL transformer compliant with the JAXP
+specification. It depends on the GNU DOM and XPath implementations, and
+will generate GNU DOM nodes unless a specific target from another
+implementation was given. It understands DOM, SAX, and stream sources
+and result sinks and supports these JAXP features.
+</div>
+
+<div>
+To use this transformer, set the system property
+<code>javax.xml.transform.TransformerFactory</code> to the value
+<code>gnu.xml.transform.TransformerFactoryImpl</code>. You can then
+instantiate <a href='TransformerFactory.html'>TransformerFactory</a>
+and transformers in the ordinary manner. Reuse of stylesheets is
+supported using the JAXP <a href='Templates.html'>Templates</a>
+mechanism.
+</div>
+
+<h3>Architecture</h3>
+
+<div>
+When given a stylesheet source, this implementation compiles it internally
+into a Stylesheet object, which is a container for templates and state.
+Each stylesheet instruction is represented by a subclass of TemplateNode,
+which is arranged in a directed graph: each TemplateNode has a reference
+to its first child and the next node.
+</div>
+
+<div>
+The transformation process consists of identifying the Template that matches
+the root of the source context, and calling <code>apply</code> on its
+corresponding TemplateNode. This in turn processes its children and next
+TemplateNode, depending on the semantics of each node type.
+</div>
+
+<div>
+Template nodes may reference XPath expressions or patterns. These are fully
+compiled to objects of type <a href='../xpath/Expr.html'>Expr</a> at the
+time the stylesheet is compiled.
+</div>
+
+<h3>Conformance</h3>
+
+<div>
+This implementation is feature complete, but the XSLT specification is
+large and there are still many bugs that need to be ironed out. It has
+been tested against the OASIS XSLT TC test suite, comprising unit tests
+from the Xalan project and Microsoft. Conformance to these unit tests
+is approximately 70% at the current time, although normal usage of the
+transformer should involve relatively few surprises (the test suite is
+designed to test very complex and obscure functionality).
+</div>
+
+<h3>Known bugs</h3>
+
+<ul>
+<li>When reusing stylesheets using the JAXP Templates mechanism, XSL
+<code>apply-imports</code> instructions will not work.</li>
+<li>XPath filter expressions do not always work as expected (this is a
+problem with the GNU XPath implementation rather than the transformer).
+This can result in problems with the <code>position()</code> function,
+as well as <code>select</code> expressions and numbering.</li>
+</ul>
+
+<div>
+Obviously we'd like to improve conformance and fix these bugs. If you're
+interested in working on any of these issues please
+<a href='mailto:classpathx-xml@gnu.org'>contact us</a>.
+</div>
+
+</body>
+</html>
diff --git a/libjava/classpath/gnu/xml/util/DoParse.java b/libjava/classpath/gnu/xml/util/DoParse.java
new file mode 100644
index 000000000..02c80d3a2
--- /dev/null
+++ b/libjava/classpath/gnu/xml/util/DoParse.java
@@ -0,0 +1,302 @@
+/* DoParse.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.util;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.io.IOException;
+
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.XMLReaderFactory;
+
+import gnu.xml.pipeline.EventConsumer;
+import gnu.xml.pipeline.EventFilter;
+import gnu.xml.pipeline.NSFilter;
+import gnu.xml.pipeline.PipelineFactory;
+import gnu.xml.pipeline.TeeConsumer;
+import gnu.xml.pipeline.ValidationConsumer;
+import gnu.xml.pipeline.WellFormednessFilter;
+
+/**
+ * This class provides a driver which may be invoked from the command line
+ * to process a document using a SAX2 parser and a specified XML processing
+ * pipeline.
+ * This facilitates some common types of command line tools, such as parsing an
+ * XML document in order test it for well formedness or validity.
+ *
+ * <p>The SAX2 XMLReaderFactory should return a SAX2 XML parser which
+ * supports both of the standardized extension handlers (for declaration
+ * and lexical events). That parser will be used to produce events.
+ *
+ * <p>The first parameter to the command gives the name of the document that
+ * will be given to that processor. If it is a file name, it is converted
+ * to a URL first.
+ *
+ * <p>The second parameter describes a simple processing pipeline, and will
+ * be used as input to {@link gnu.xml.pipeline.PipelineFactory}
+ * methods which identify the processing to be done. Examples of such a
+ * pipeline include <pre>
+ *
+ * nsfix | validate <em>to validate the input document </em>
+ * nsfix | write ( stdout ) <em>to echo the file as XML text</em>
+ * dom | nsfix | write ( stdout ) <em>parse into DOM, print the result</em>
+ * </pre>
+ *
+ * <p> Relatively complex pipelines can be described on the command line, but
+ * not all interesting ones will require as little configuration as can be done
+ * in that way. Put filters like "nsfix", perhaps followed by "validate",
+ * at the front of the pipeline so they can be optimized out if a parser
+ * supports those modes natively.
+ *
+ * <p> If the parsing is aborted for any reason, the JVM will exit with a
+ * failure code. If a validating parse was done then both validation and
+ * well formedness errors will cause a failure. A non-validating parse
+ * will report failure on well formedness errors.
+ *
+ * @see gnu.xml.pipeline.PipelineFactory
+ *
+ * @author David Brownell
+ */
+final public class DoParse
+{
+ private DoParse () { /* no instances allowed */ }
+
+ // first reported nonrecoverable error
+ private static SAXParseException fatal;
+
+ // error categories
+ private static int errorCount;
+ private static int fatalCount;
+
+ /**
+ * Command line invoker for this class; pass a filename or URL
+ * as the first argument, and a pipeline description as the second.
+ * Make sure to use filters to condition the input to stages that
+ * require it; an <em>nsfix</em> filter will be a common requirement,
+ * to restore syntax that SAX2 parsers delete by default. Some
+ * conditioning filters may be eliminated by setting parser options.
+ * (For example, "nsfix" can set the "namespace-prefixes" feature to
+ * a non-default value of "true". In the same way, "validate" can set
+ * the "validation" feature to "true".)
+ */
+ public static void main (String argv [])
+ throws IOException
+ {
+ int exitStatus = 1;
+
+ if (argv.length != 2) {
+ System.err.println ("Usage: DoParse [filename|URL] pipeline-spec");
+ System.err.println ("Example pipeline specs:");
+ System.err.println (" 'nsfix | validate'");
+ System.err.println (
+ " ... restore namespace syntax, validate");
+ System.err.println (" 'nsfix | write ( stdout )'");
+ System.err.println (
+ " ... restore namespace syntax, write to stdout as XML"
+ );
+ System.exit (1);
+ }
+
+ try {
+ //
+ // Get input source for specified document (or try ;-)
+ //
+ argv [0] = Resolver.getURL (argv [0]);
+ InputSource input = new InputSource (argv [0]);
+
+ //
+ // Get the producer, using the system default parser (which
+ // can be overridden for this particular invocation).
+ //
+ // And the pipeline, using commandline options.
+ //
+ XMLReader producer;
+ EventConsumer consumer;
+
+ producer = XMLReaderFactory.createXMLReader ();
+
+ //
+ // XXX pipeline factory now has a pre-tokenized input
+ // method, use it ... that way at least some params
+ // can be written using quotes (have spaces, ...)
+ //
+ consumer = PipelineFactory.createPipeline (argv [1]);
+
+ //
+ // XXX want commandline option for tweaking error handler.
+ // Want to be able to present warnings.
+ //
+ producer.setErrorHandler (new MyErrorHandler ());
+
+ // XXX need facility enabling resolving to local DTDs
+
+ //
+ // Parse. The pipeline may get optimized a bit, so we
+ // can't always fail cleanly for validation without taking
+ // a look at the filter stages.
+ //
+ EventFilter.bind (producer, consumer);
+ producer.parse (input);
+
+ try {
+ if (producer.getFeature (
+ "http://org.xml/sax/features/validation"))
+ exitStatus = ((errorCount + fatalCount) > 0) ? 1 : 0;
+ else if (fatalCount == 0)
+ exitStatus = 0;
+ } catch (SAXException e) {
+ if (hasValidator (consumer))
+ exitStatus = ((errorCount + fatalCount) > 0) ? 1 : 0;
+ else if (fatalCount == 0)
+ exitStatus = 0;
+ }
+
+ } catch (java.net.MalformedURLException e) {
+ System.err.println ("** Malformed URL: " + e.getMessage ());
+ System.err.println ("Is '" + argv [0] + "' a non-existent file?");
+ e.printStackTrace ();
+ // e.g. FNF
+
+ } catch (SAXParseException e) {
+ if (e != fatal) {
+ System.err.print (printParseException ("Parsing Aborted", e));
+ e.printStackTrace ();
+ if (e.getException () != null) {
+ System.err.println ("++ Wrapped exception:");
+ e.getException ().printStackTrace ();
+ }
+ }
+
+ } catch (SAXException e) {
+ Exception x = e;
+ if (e.getException () != null)
+ x = e.getException ();
+ x.printStackTrace ();
+
+ } catch (Throwable t) {
+ t.printStackTrace ();
+ }
+
+ System.exit (exitStatus);
+ }
+
+ // returns true if saw a validator (before end or unrecognized node)
+ // false otherwise
+ private static boolean hasValidator (EventConsumer e)
+ {
+ if (e == null)
+ return false;
+ if (e instanceof ValidationConsumer)
+ return true;
+ if (e instanceof TeeConsumer) {
+ TeeConsumer t = (TeeConsumer) e;
+ return hasValidator (t.getFirst ())
+ || hasValidator (t.getRest ());
+ }
+ if (e instanceof WellFormednessFilter
+ || e instanceof NSFilter
+ )
+ return hasValidator (((EventFilter)e).getNext ());
+
+ // else ... gee, we can't know. Assume not.
+
+ return false;
+ }
+
+ static class MyErrorHandler implements ErrorHandler
+ {
+ // dump validation errors, but continue
+ public void error (SAXParseException e)
+ throws SAXParseException
+ {
+ errorCount++;
+ System.err.print (printParseException ("Error", e));
+ }
+
+ public void warning (SAXParseException e)
+ throws SAXParseException
+ {
+ // System.err.print (printParseException ("Warning", e));
+ }
+
+ // try to continue fatal errors, in case a parser reports more
+ public void fatalError (SAXParseException e)
+ throws SAXParseException
+ {
+ fatalCount++;
+ if (fatal == null)
+ fatal = e;
+ System.err.print (printParseException ("Nonrecoverable Error", e));
+ }
+ }
+
+ static private String printParseException (
+ String label,
+ SAXParseException e
+ ) {
+ CPStringBuilder buf = new CPStringBuilder ();
+ int temp;
+
+ buf.append ("** ");
+ buf.append (label);
+ buf.append (": ");
+ buf.append (e.getMessage ());
+ buf.append ('\n');
+ if (e.getSystemId () != null) {
+ buf.append (" URI: ");
+ buf.append (e.getSystemId ());
+ buf.append ('\n');
+ }
+ if ((temp = e.getLineNumber ()) != -1) {
+ buf.append (" line: ");
+ buf.append (temp);
+ buf.append ('\n');
+ }
+ if ((temp = e.getColumnNumber ()) != -1) {
+ buf.append (" char: ");
+ buf.append (temp);
+ buf.append ('\n');
+ }
+
+ return buf.toString ();
+ }
+}
diff --git a/libjava/classpath/gnu/xml/util/DomParser.java b/libjava/classpath/gnu/xml/util/DomParser.java
new file mode 100644
index 000000000..66e3f1d87
--- /dev/null
+++ b/libjava/classpath/gnu/xml/util/DomParser.java
@@ -0,0 +1,804 @@
+/* DomParser.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.util;
+
+import java.util.Enumeration;
+import java.util.Locale;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.AttributesImpl;
+import org.xml.sax.helpers.NamespaceSupport;
+import org.xml.sax.ext.DeclHandler;
+import org.xml.sax.ext.DefaultHandler2;
+import org.xml.sax.ext.LexicalHandler;
+
+import org.w3c.dom.*;
+
+
+/**
+ * This parser emits SAX2 parsing events as it traverses a DOM tree, using
+ * any conformant implementation of DOM. It exposes all SAX1 features,
+ * and the following SAX2 features and properties (as
+ * identified by standard URIs which are not fully provided here). Note
+ * that if a Level 1 DOM implementation is given, then this behaves as if
+ * namespaces were disabled, and namespace prefixes were enabled. </p>
+ *
+ * <table border="1" width='100%' cellpadding='3' cellspacing='0'>
+ * <tr bgcolor='#ccccff'>
+ * <th><font size='+1'>Name</font></th>
+ * <th><font size='+1'>Notes</font></th></tr>
+ *
+ * <tr><td colspan=2><center><em>Features ... URL prefix is
+ * <b>http://xml.org/sax/features/</b></em></center></td></tr>
+ *
+ * <tr><td>(URL)/external-general-entities</td>
+ * <td>false (does no parsing)</td></tr>
+ * <tr><td>(URL)/external-parameter-entities</td>
+ * <td>false (does no parsing)</td></tr>
+ * <tr><td>(URL)/namespaces</td>
+ * <td>Value is fixed at <em>true</em></td></tr>
+ * <tr><td>(URL)/namespace-prefixes</td>
+ * <td>Value is settable, defaulting to <em>false</em>
+ * (<code>xmlns</code> attributes hidden, and names aren't prefixed)
+ * </td></tr>
+ * <tr><td>(URL)/string-interning</td>
+ * <td>Value is fixed at <em>false</em> (DOM provides no
+ * guarantees as to interning)</td></tr>
+ * <tr><td>(URL)/validation</td>
+ * <td>false (does no parsing)</td></tr>
+ * <tr><td>(URL)/lexical-handler/parameter-entities</td>
+ * <td>false (DOM doesn't do parameter entities)</td></tr>
+ *
+ * <tr><td colspan=2><center><em>Properties ... URL prefix is
+ * <b>http://xml.org/sax/properties/</b></em></center></td></tr>
+ *
+ *
+ * <tr><td>(URL)/dom-node</td>
+ * <td>This property may be set before parsing to hold a DOM
+ * <em>Document</em> node; any arguments given to <em>parse</em>
+ * methods are ignored. When retrieved
+ * during a parse, this value contains the "current" DOM node.
+ * </td></tr>
+ * <tr><td>(URL)/declaration-handler</td>
+ * <td>A declaration handler may be provided. Declaration of external
+ * general entities is exposed, but not parameter entities; none of the
+ * entity names reported here will begin with "%". </td></tr>
+ * <tr><td>(URL)/lexical-handler</td>
+ * <td>A lexical handler may be provided. While the start and end of
+ * any external subset are reported, expansion of other parameter
+ * entities (e.g. inside attribute list declarations) is not exposed.
+ * Expansion of general entities within attributes is also not exposed
+ * (see below).</td></tr>
+ * </table>
+ *
+ * <P> The consequences of modifying a DOM document tree as it is being walked
+ * by this "parser" are unspecified; don't do it! </P>
+ *
+ * @author David Brownell
+ */
+final public class DomParser implements XMLReader
+{
+ // Stuff used internally to route events correctly
+ private DefaultHandler2 defaultHandler = new DefaultHandler2 ();
+
+ // per-parse SAX stuff
+ private ContentHandler contentHandler = defaultHandler;
+ private DTDHandler dtdHandler = defaultHandler;
+ private DeclHandler declHandler = defaultHandler;
+ private LexicalHandler lexicalHandler = defaultHandler;
+
+ // shared context
+ private ErrorHandler errHandler = defaultHandler;
+ private EntityResolver resolver = defaultHandler;
+ private Locale locale = Locale.getDefault ();
+
+ // parser state
+ private Node start;
+ private Node current;
+ private boolean isL2;
+ private boolean showNamespaces = true;
+ private boolean showXML1_0 = false;
+ private NamespaceSupport prefixStack = new NamespaceSupport ();
+ private boolean isDocument;
+
+
+ /**
+ * Constructs an unitialized <b>SAX2</b> parser.
+ */
+ public DomParser () {
+ }
+
+ /**
+ * Constructs an <b>SAX2</b> parser initialized to traverse the specified
+ * DOM tree. If the node is a document, the startDocument() and
+ * endDocument() calls bracket the calls exposing children.
+ */
+ public DomParser (Node node) {
+ setStart (node);
+ }
+
+
+ // stuff that most components in an application should be sharing:
+ // resolver and error locale.
+
+ /**
+ * <b>SAX2</b>: Returns the object used when resolving external
+ * entities during parsing (both general and parameter entities).
+ */
+ public EntityResolver getEntityResolver ()
+ {
+ return resolver;
+ }
+
+ /**
+ * <b>SAX1</b>: Provides an object which may be used when resolving external
+ * entities during parsing (both general and parameter entities).
+ */
+ public void setEntityResolver (EntityResolver resolver)
+ {
+ if (resolver == null)
+ resolver = defaultHandler;
+ this.resolver = resolver;
+ }
+
+ /**
+ * <b>SAX1</b>: Identifies the locale which the parser should use for the
+ * diagnostics it provides.
+ *
+ * @exception SAXException as defined in the specification for
+ * <em>org.xml.sax.Parser.setLocale()</em>
+ */
+ public void setLocale (Locale locale)
+ throws SAXException
+ {
+ if (locale == null)
+ locale = Locale.getDefault ();
+ this.locale = locale;
+ }
+
+
+ // different modules will tend to handle error handling the same,
+ // but it may not be the same through the whole app
+
+ /**
+ * <b>SAX2</b>: Returns the object used to receive callbacks for XML
+ * errors of all levels (fatal, nonfatal, warning).
+ */
+ public ErrorHandler getErrorHandler ()
+ {
+ return errHandler;
+ }
+
+ /**
+ * <b>SAX1</b>: Provides an object which receives callbacks for XML errors
+ * of all levels (fatal, nonfatal, warning).
+ */
+ public void setErrorHandler (ErrorHandler handler)
+ {
+ if (handler == null)
+ handler = defaultHandler;
+ errHandler = handler;
+ }
+
+
+ // stuff different parts of a module will handle differently
+
+ /**
+ * <b>SAX2</b>: Returns the object used to report the logical
+ * content of an XML document.
+ */
+ public ContentHandler getContentHandler ()
+ {
+ return contentHandler;
+ }
+
+ /**
+ * <b>SAX2</b>: Assigns the object used to report the logical
+ * content of an XML document.
+ */
+ public void setContentHandler (ContentHandler handler)
+ {
+ if (handler == null)
+ handler = defaultHandler;
+ contentHandler = handler;
+ }
+
+ /**
+ * <b>SAX2</b>: Returns the object used to process declarations related
+ * to notations and unparsed entities.
+ */
+ public DTDHandler getDTDHandler ()
+ {
+ return dtdHandler;
+ }
+
+ /**
+ * <b>SAX1</b>: Provides an object which may be used to intercept
+ * declarations related to notations and unparsed entities.
+ */
+ public void setDTDHandler (DTDHandler handler)
+ {
+ if (handler == null)
+ handler = defaultHandler;
+ dtdHandler = handler;
+ }
+
+
+ /**
+ * <b>SAX1</b>: Parses the previously provided DOM document (the
+ * input parameter is ignored). When this returns, that same
+ * document may be parsed again without needing a "reset".
+ *
+ * @param uri ignored (pass an empty string)
+ * @exception SAXException as defined in the specification for
+ * <em>org.xml.sax.Parser.parse()</em>
+ */
+ public void parse (String uri) throws SAXException
+ {
+ parse ();
+ }
+
+ /**
+ * <b>SAX1</b>: Parses the previously provided DOM document (the
+ * input parameter is ignored). When this returns, that same
+ * document may be parsed again without needing a "reset".
+ *
+ * @param input ignored
+ * @exception SAXException as defined in the specification for
+ * <em>org.xml.sax.Parser.parse()</em>
+ */
+ public void parse (InputSource input) throws SAXException
+ {
+ parse ();
+ }
+
+ private void parse () throws SAXException
+ {
+ try {
+ walk ();
+ } finally {
+ if (isDocument)
+ contentHandler.endDocument ();
+ current = null;
+ prefixStack.reset ();
+ }
+ }
+
+ private boolean getIsL2 (Node node)
+ {
+ DOMImplementation impl;
+ Document doc;
+
+ if (node instanceof Document)
+ doc = (Document) node;
+ else
+ doc = node.getOwnerDocument ();
+ if (doc == null)
+ throw new RuntimeException ("? unowned node - L2 DTD ?");
+ impl = doc.getImplementation ();
+ return impl.hasFeature ("XML", "2.0");
+ }
+
+
+ private static final String FEATURES = "http://xml.org/sax/features/";
+ private static final String HANDLERS = "http://xml.org/sax/properties/";
+
+ /**
+ * <b>SAX2</b>: Tells whether this parser supports the specified feature.
+ */
+ public boolean getFeature (String name)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ // basically, none are relevant -- they relate more to
+ // parsing than to walking a "parse tree".
+
+ // FIXME: DOM feature to expose interning?
+
+ if ((FEATURES + "validation").equals (name)
+ || (FEATURES + "external-general-entities")
+ .equals (name)
+ || (FEATURES + "external-parameter-entities")
+ .equals (name)
+ || (FEATURES + "string-interning").equals (name)
+ )
+ return false;
+
+ if ((FEATURES + "namespaces").equals (name))
+ return showNamespaces;
+ if ((FEATURES + "namespace-prefixes").equals (name))
+ return showXML1_0;
+
+ throw new SAXNotRecognizedException (name);
+ }
+
+ /**
+ * <b>SAX2</b>: Returns the specified property. At this time only
+ * the declaration and lexical handlers, and current the "DOM" node,
+ * are supported.
+ */
+ public Object getProperty (String name)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ if ((HANDLERS + "declaration-handler").equals (name))
+ return declHandler == defaultHandler ? null : declHandler;
+ if ((HANDLERS + "lexical-handler").equals (name))
+ return lexicalHandler == defaultHandler ? null : lexicalHandler;
+
+ if ((HANDLERS + "dom-node").equals (name))
+ return current;
+
+ // unknown properties
+ throw new SAXNotRecognizedException (name);
+ }
+
+ /**
+ * <b>SAX2</b>: Sets the state of features supported in this parser.
+ * Only the namespace support features are mutable.
+ */
+ public void setFeature (String name, boolean state)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ if (current != null)
+ throw new IllegalStateException ("feature change midparse");
+
+ boolean value = getFeature (name);
+
+ if (value == state)
+ return;
+
+ if ((FEATURES + "namespaces").equals (name)) {
+ if (!showXML1_0 && state == false)
+ throw new SAXNotSupportedException ("Illegal namespace "
+ + "processing configuration");
+ showNamespaces = state;
+ return;
+ }
+ if ((FEATURES + "namespace-prefixes").equals (name)) {
+ if (!showNamespaces && state == false)
+ throw new SAXNotSupportedException ("Illegal namespace "
+ + "processing configuration");
+ showXML1_0 = state;
+ return;
+ }
+
+ throw new SAXNotSupportedException (name);
+ }
+
+ /**
+ * <b>SAX2</b>: Assigns the specified property. At this time only
+ * declaration and lexical handlers, and the initial DOM document, are
+ * supported. These must not be changed to values of the wrong type.
+ * Like SAX1 handlers, these handlers may be changed at any time.
+ * Like SAX1 input source or document URI, the initial DOM document
+ * may not be changed during a parse.
+ */
+ public void setProperty (String name, Object state)
+ throws SAXNotRecognizedException, SAXNotSupportedException
+ {
+ if ((HANDLERS + "declaration-handler").equals (name)) {
+ if (!(state instanceof DeclHandler || state == null))
+ throw new SAXNotSupportedException (name);
+ declHandler = (DeclHandler) state;
+ return;
+ }
+
+ if ((HANDLERS + "lexical-handler").equals (name)) {
+ if (!(state instanceof LexicalHandler || state == null))
+ throw new SAXNotSupportedException (name);
+ lexicalHandler = (LexicalHandler) state;
+ return;
+ }
+
+ if ((HANDLERS + "dom-node").equals (name)) {
+ if (state == null || state instanceof Node) {
+ if (current != null)
+ throw new SAXNotSupportedException (
+ "property is readonly during parse: " + name);
+ setStart ((Node) state);
+ return;
+ }
+ throw new SAXNotSupportedException ("not a DOM Node");
+ }
+
+ // unknown properties
+ throw new SAXNotRecognizedException (name);
+ }
+
+ private void setStart (Node property)
+ {
+ start = property;
+ if (start != null) {
+ isL2 = getIsL2 (start);
+ isDocument = (start instanceof Document);
+ }
+ }
+
+ //
+ // Non-recursive walk, using DOM state when backtracking is needed
+ //
+ private void walk ()
+ throws SAXException
+ {
+ int type;
+ NamedNodeMap nodes;
+ int length;
+ AttributesImpl attrs = new AttributesImpl ();
+ char chars [];
+ String ns, local;
+
+ synchronized (this) {
+ if (current != null)
+ throw new IllegalStateException ("already walking tree");
+
+ // JVM guarantees assignments are atomic; so no other
+ // thread could get this far till this walk's done.
+ current = start;
+ }
+
+ for (;;) {
+ type = current.getNodeType ();
+
+ //
+ // First, visit the current node, including any "start" calls
+ //
+ switch (type) {
+
+ case Node.DOCUMENT_NODE:
+ contentHandler.startDocument ();
+ break;
+
+ case Node.ELEMENT_NODE:
+ nodes = current.getAttributes ();
+ length = nodes.getLength ();
+ prefixStack.pushContext ();
+ for (int i = 0; i < length; i++) {
+ Attr attr = (Attr) nodes.item (i);
+ String name = attr.getNodeName ();
+
+ if (showNamespaces && name.startsWith ("xmlns")) {
+ String prefix;
+ String uri;
+
+ // NOTE: DOM L2 (CR2+ and REC) violate the
+ // Namespaces REC, treat "xmlns" like a strange
+ // attribute instead of a magic token
+ if ("xmlns".equals (name))
+ prefix = "";
+ else
+ prefix = name.substring (6);
+ uri = attr.getNodeValue ();
+
+ prefixStack.declarePrefix (prefix, uri);
+ contentHandler.startPrefixMapping (prefix, uri);
+
+ if (!showXML1_0)
+ continue;
+ }
+
+ //
+ // NOTE: DOM doesn't record the attribute type info
+ // which SAX exposes; so this always reports CDATA.
+ //
+ // NOTE: SAX doesn't expose the isSpecified info which
+ // DOM exposes; that's discarded here. Similarly with
+ // the information DOM hides inside itself about what
+ // the default values for an attribute are.
+ //
+ if (showNamespaces) {
+ if (isL2) {
+ if ((ns = attr.getNamespaceURI ()) == null)
+ ns = "";
+ // Note: SAX2 and DOM handle "local" names
+ // differently
+ if ((local = attr.getLocalName ()) == null)
+ local = name;
+ } else {
+// XXX
+ throw new RuntimeException (
+ "NYI, ns lookup when parsing L1 DOM");
+ }
+ } else
+ ns = local = "";
+ attrs.addAttribute (ns, local, name,
+ "CDATA", attr.getNodeValue ());
+ }
+ if (showNamespaces) {
+ if (isL2) {
+ if ((ns = current.getNamespaceURI ()) == null)
+ ns = "";
+ // Note: SAX2 and DOM handle "local" names differently
+ if ((local = current.getLocalName ()) == null)
+ local = current.getNodeName ();
+ } else {
+// XXX
+ throw new RuntimeException (
+ "NYI, ns lookup when parsing L1 DOM");
+ }
+ } else
+ ns = local = "";
+ contentHandler.startElement (ns, local,
+ current.getNodeName (), attrs);
+ if (length != 0)
+ attrs.clear ();
+ break;
+
+ case Node.CDATA_SECTION_NODE:
+ lexicalHandler.startCDATA ();
+ chars = current.getNodeValue ().toCharArray ();
+ contentHandler.characters (chars, 0, chars.length);
+ lexicalHandler.endCDATA ();
+ break;
+
+ case Node.COMMENT_NODE:
+ chars = current.getNodeValue ().toCharArray ();
+ lexicalHandler.comment (chars, 0, chars.length);
+ break;
+
+ case Node.DOCUMENT_TYPE_NODE:
+ {
+ DocumentType doctype = (DocumentType) current;
+
+ //
+ // Only DOM L2 supports recreating even some DTDs in full.
+ //
+ if (isL2) {
+ lexicalHandler.startDTD (doctype.getName (),
+ doctype.getPublicId (),
+ doctype.getSystemId ());
+ } else
+ lexicalHandler.startDTD (doctype.getName (),
+ null, null);
+
+ //
+ // The only sure way to recreate is to provide both the
+ // internal and external subsets. Otherwise, only part
+ // of the job can be done ... because from the DTD, DOM
+ // discards both the critical data, like the attribute and
+ // element declarations, as well as the PIs and comments
+ // that are used to hold their documentation.
+ //
+ // Even the entity and notation declarations that it can
+ // expose can't be recorded without proprietary extensions.
+ //
+ // We construct a comment to tell what we know about how
+ // (in)complete this particular really DTD is.
+ //
+ {
+ String message;
+ char buf [];
+
+ //
+ // Though DOM L2 lets the whole doctype be recreated,
+ // SAX2 can't represent it (input or output).
+ // So this will be the typical case.
+ //
+ if (isL2 && doctype.getInternalSubset () != null)
+ message =
+ " Full DTD known; can't be shown using SAX2. ";
+
+ //
+ // Otherwise, we'll concoct a partial DTD. If there's
+ // any more data here at all, it was provided using a
+ // (proprietary) extension to DOM.
+ //
+ else
+ message =
+ " This DTD was was recreated using incomplete DOM L2 records. ";
+
+ buf = message.toCharArray ();
+ lexicalHandler.comment (buf, 0, buf.length);
+ }
+
+ // report notations first
+ nodes = doctype.getNotations ();
+ length = nodes.getLength ();
+ for (int i = 0; i < length; i++) {
+ Notation notation = (Notation) nodes.item (i);
+ dtdHandler.notationDecl (
+ notation.getNodeName (),
+ notation.getPublicId (),
+ notation.getSystemId ());
+ }
+
+ // then parsed and unparsed external general entities
+ nodes = doctype.getEntities ();
+ length = nodes.getLength ();
+ for (int i = 0; i < length; i++) {
+ Entity entity = (Entity) nodes.item (i);
+ String notation = entity.getNotationName ();
+
+ if (notation != null)
+ dtdHandler.unparsedEntityDecl (
+ entity.getNodeName (),
+ entity.getPublicId (),
+ entity.getSystemId (),
+ notation);
+ else if (entity.getSystemId () != null)
+ declHandler.externalEntityDecl (
+ entity.getNodeName (),
+ entity.getPublicId (),
+ entity.getSystemId ());
+
+ //
+ // NOTE: DOM doesn't clearly provide internal
+ // entity support; but in case someone tries to
+ // fudge such support, we defend ourselves above.
+ //
+ // NOTE: DOM doesn't expose parameter entities
+ // (thank you thank you thank you thank you)
+ //
+ }
+
+ //
+ // NOTE: DOM (levels 1 and 2) doesn't expose real
+ // typing information (element or attribute decls),
+ // as exposed by SAX2 declaration handlers.
+ //
+ lexicalHandler.endDTD ();
+ }
+ break;
+
+ case Node.ENTITY_REFERENCE_NODE:
+ // this isn't done except (a) in content, and
+ // (b) not within a start tag (att value)
+ lexicalHandler.startEntity (current.getNodeName ());
+ break;
+
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ contentHandler.processingInstruction (
+ current.getNodeName (), current.getNodeValue ());
+ break;
+
+ case Node.TEXT_NODE:
+ chars = current.getNodeValue ().toCharArray ();
+ contentHandler.characters (chars, 0, chars.length);
+ break;
+
+ default:
+ // e.g. fragments, entities, notations, attributes
+ throw new SAXException ("Illegal DOM Node type in Document: "
+ + current.getNodeType ());
+ }
+
+ //
+ // Then, pick the next node to visit. If the next node isn't
+ // a child, an "end" call may be needed before moving on.
+ // If there's no next node, we're done.
+ //
+ Node next;
+
+ switch (type) {
+ case Node.DOCUMENT_NODE:
+ case Node.ELEMENT_NODE:
+ case Node.ENTITY_REFERENCE_NODE:
+ //
+ // For elements that can have children, visit those
+ // children before any siblings (i.e. depth first)
+ // and after visiting this node (i.e. preorder)
+ //
+ next = current.getFirstChild ();
+ if (next != null) {
+ current = next;
+ break;
+ }
+ //
+ // Else treat this like other childless nodes, but
+ // handle this node's "end" immediately.
+ //
+ callEnd (current);
+
+ // FALLTHROUGH
+
+ case Node.CDATA_SECTION_NODE:
+ case Node.COMMENT_NODE:
+ case Node.DOCUMENT_TYPE_NODE:
+ case Node.ENTITY_NODE:
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ case Node.TEXT_NODE:
+ //
+ // Use next sibling, if there is one.
+ // Else, climb up a level (calling "end")
+ // until we find an ancestral sibling
+ // or until we we climb off the top (FINISH)
+ //
+ for (;;) {
+ if ((next = current.getNextSibling ()) != null)
+ break;
+ current = current.getParentNode ();
+ if (current == null || current == start)
+ return;
+ callEnd (current);
+ }
+ current = next;
+ break;
+
+ default:
+ throw new SAXException (
+ "Illegal DOM Node type found: " + current.getNodeType ());
+ }
+ }
+ }
+
+ private void callEnd (Node node) throws SAXException
+ {
+ switch (node.getNodeType ()) {
+ // only these three container types may ever be found
+ // directly inside a Document.
+ case Node.DOCUMENT_NODE:
+ // for SAX conformance, endDocument must always
+ // be called ... it's done in a "finally" clause)
+ return;
+
+ case Node.ELEMENT_NODE:
+ if (showNamespaces) {
+ if (isL2)
+ contentHandler.endElement (
+ node.getNamespaceURI (),
+ node.getLocalName (),
+ node.getNodeName ());
+ else
+// XXX
+ throw new RuntimeException (
+ "NYI, ns lookup when parsing L1 DOM");
+ for (Enumeration e = prefixStack.getDeclaredPrefixes ();
+ e.hasMoreElements ();
+ ) {
+ contentHandler.endPrefixMapping ((String) e.nextElement ());
+ }
+ } else
+ contentHandler.endElement ("", "", node.getNodeName ());
+ prefixStack.popContext ();
+ return;
+
+ case Node.ENTITY_REFERENCE_NODE:
+ // see above -- in content, outside start tags.
+ lexicalHandler.endEntity (node.getNodeName ());
+ return;
+
+ // these can be given at the top level
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ case Node.ATTRIBUTE_NODE:
+ return;
+
+ default:
+ throw new SAXException (
+ "Illegal DOM container type found: "
+ + current.getNodeType ());
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/xml/util/Resolver.java b/libjava/classpath/gnu/xml/util/Resolver.java
new file mode 100644
index 000000000..b16f9617f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/util/Resolver.java
@@ -0,0 +1,263 @@
+/* Resolver.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.util;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Dictionary;
+
+import org.xml.sax.EntityResolver;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Utility implementation of a SAX resolver, which can be used to improve
+ * network utilization of SAX based XML components. It does this by
+ * supporting local caches of external entities.
+ * SAX parsers <em>should</em> use such local caches when possible.
+ *
+ * @see XCat
+ */
+public class Resolver implements EntityResolver, Cloneable
+{
+ /**
+ * Updates a dictionary used to map PUBLIC identifiers to file names,
+ * so that it uses the mappings in a specified directory.
+ *
+ * @param mappings Array of string pairs, where the first member
+ * of each pair is a PUBLIC identifier and the second is the
+ * name of a file, relative to the specified directory.
+ * @param directory File holding the specified files.
+ */
+ public static void addDirectoryMapping (
+ Dictionary table,
+ String mappings [][],
+ File directory
+ ) throws IOException
+ {
+ for (int i = 0; i < mappings.length; i++) {
+ File file = new File (directory, mappings [i][1]);
+ String temp;
+
+ if (!file.exists ()) // ?? log a warning ??
+ continue;
+
+ temp = fileToURL (file);
+ table.put (mappings [i][0], temp);
+ }
+ }
+
+ // FIXME: these *URL routines don't quite belong here, except
+ // that they're all in the same spirit of making it easy to
+ // use local filesystem URIs with XML parsers.
+
+ /**
+ * Provides the URL for a named file, without relying on the JDK 1.2
+ * {@link java.io.File#toURL File.toURL}() utility method.
+ *
+ * @param filename the file name to convert. Relative file names
+ * are resolved the way the JVM resolves them (current to the
+ * process-global current working directory).
+ *
+ * @exception IOException if the file does not exist
+ */
+ public static String fileNameToURL (String filename)
+ throws IOException
+ {
+ return fileToURL (new File (filename));
+ }
+
+ /**
+ * Provides the URL for a file, without relying on the JDK 1.2
+ * {@link java.io.File#toURL File.toURL}() utility method.
+ *
+ * @param f the file to convert. Relative file names
+ * are resolved the way the JVM resolves them (current to the
+ * process-global current working directory).
+ *
+ * @exception IOException if the file does not exist
+ */
+ public static String fileToURL (File f)
+ throws IOException
+ {
+ String temp;
+
+ // NOTE: the javax.xml.parsers.DocumentBuilder and
+ // javax.xml.transform.stream.StreamSource versions
+ // of this don't have this test. Some JVM versions
+ // don't report this error sanely through URL code.
+ if (!f.exists ())
+ throw new IOException ("no such file: " + f.getName ());
+
+ // FIXME: getAbsolutePath() seems buggy; I'm seeing components
+ // like "/foo/../" which are clearly not "absolute"
+ // and should have been resolved with the filesystem.
+
+ // Substituting "/" would be wrong, "foo" may have been
+ // symlinked ... the URL code will make that change
+ // later, so that things can get _really_ broken!
+
+ temp = f.getAbsolutePath ();
+
+ if (File.separatorChar != '/')
+ temp = temp.replace (File.separatorChar, '/');
+ if (!temp.startsWith ("/"))
+ temp = "/" + temp;
+ if (!temp.endsWith ("/") && f.isDirectory ())
+ temp = temp + "/";
+ return "file:" + temp;
+ }
+
+
+ /**
+ * Returns a URL string. Note that if a malformed URL is provided, or
+ * the parameter names a nonexistent file, the resulting URL may be
+ * malformed.
+ *
+ * @param fileOrURL If this is the name of a file which exists,
+ * then its URL is returned. Otherwise the argument is returned.
+ */
+ public static String getURL (String fileOrURL)
+ {
+ try {
+ return fileNameToURL (fileOrURL);
+ } catch (Exception e) {
+ return fileOrURL;
+ }
+ }
+
+
+
+ // note: cloneable, this is just copied; unguarded against mods
+ private Dictionary pubidMapping;
+
+ /**
+ * Constructs a resolver which understands how to map PUBLIC identifiers
+ * to other URIs, typically for local copies of standard DTD components.
+ *
+ * @param dict maps PUBLIC identifiers to URIs. This is not
+ * copied; subsequent modifications will be reported through the
+ * resolution operations.
+ */
+ public Resolver (Dictionary dict)
+ { pubidMapping = dict; }
+
+
+ // FIXME: want notion of a "system default" resolver, presumably
+ // loaded with all sorts of useful stuff. At the same time need
+ // a notion of resolver chaining (failure --> next) so that subsystems
+ // can set up things that won't interfere with other ones.
+
+ /**
+ * This parses most MIME content type strings that have <em>charset=...</em>
+ * encoding declarations to and returns the specified encoding. This
+ * conforms to RFC 3023, and is useful when constructing InputSource
+ * objects from URLConnection objects or other objects using MIME
+ * content typing.
+ *
+ * @param contentType the MIME content type that will be parsed; must
+ * not be null.
+ * @return the appropriate encoding, or null if the content type is
+ * not text and there's no <code>charset=...</code> attribute
+ */
+ static public String getEncoding (String contentType)
+ {
+ // currently a dumb parsing algorithm that works "mostly" and handles
+ // ..anything...charset=ABC
+ // ..anything...charset=ABC;otherAttr=DEF
+ // ..anything...charset=ABC (comment);otherAttr=DEF
+ // ..anything...charset= "ABC" (comment);otherAttr=DEF
+
+ int temp;
+ String encoding;
+ String defValue = null;
+
+ if (contentType.startsWith ("text/"))
+ defValue = contentType.startsWith ("text/html")
+ ? "ISO-8859-1" : "US-ASCII";
+
+ // Assumes 'charset' is only an attribute name, not part
+ // of a value, comment, or other attribute name
+ // ALSO assumes no escaped values like "\;" or "\)"
+ if ((temp = contentType.indexOf ("charset")) != -1) {
+ // strip out everything up to '=' ...
+ temp = contentType.indexOf ('=', temp);
+ if (temp == -1)
+ return defValue;
+ encoding = contentType.substring (temp + 1);
+ // ... and any subsequent attributes
+ if ((temp = encoding.indexOf (';')) != -1)
+ encoding = encoding.substring (0, temp);
+ // ... and any comments after value
+ if ((temp = encoding.indexOf ('(')) != -1)
+ encoding = encoding.substring (0, temp);
+ // ... then whitespace, and any (double) quotes
+ encoding = encoding.trim ();
+ if (encoding.charAt (0) == '"')
+ encoding = encoding.substring (1, encoding.length () - 1);
+ } else
+ encoding = defValue;
+ return encoding;
+ }
+
+
+ /**
+ * Uses a local dictionary of public identifiers to resolve URIs,
+ * normally with the goal of minimizing network traffic or latencies.
+ */
+ public InputSource resolveEntity (String publicId, String systemId)
+ throws IOException, SAXException
+ {
+ InputSource retval = null;
+ String uri;
+
+ if (publicId != null
+ && ((uri = (String) pubidMapping.get (publicId)) != null)) {
+ retval = new InputSource (uri);
+ retval.setPublicId (publicId);
+ }
+
+ // Could do URN resolution here
+
+ // URL resolution always done by parser
+
+ // FIXME: chain to "next" resolver
+
+ return retval;
+ }
+}
diff --git a/libjava/classpath/gnu/xml/util/SAXNullTransformerFactory.java b/libjava/classpath/gnu/xml/util/SAXNullTransformerFactory.java
new file mode 100644
index 000000000..3a97678e0
--- /dev/null
+++ b/libjava/classpath/gnu/xml/util/SAXNullTransformerFactory.java
@@ -0,0 +1,676 @@
+/* SAXNullTransformerFactory.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.util;
+
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Hashtable;
+import java.util.Properties;
+
+import gnu.xml.dom.Consumer;
+import gnu.xml.dom.DomDocument;
+import gnu.xml.pipeline.DomConsumer;
+import gnu.xml.pipeline.EventFilter;
+
+import javax.xml.transform.*;
+import javax.xml.transform.dom.*;
+import javax.xml.transform.sax.*;
+import javax.xml.transform.stream.*;
+
+import org.xml.sax.*;
+import org.xml.sax.helpers.XMLReaderFactory;
+import org.xml.sax.helpers.LocatorImpl;
+
+
+/**
+ * Implements null transforms. XSLT stylesheets are not supported.
+ * This class provides a way to translate three representations of
+ * XML data (SAX event stream, DOM tree, and XML text) into each other.
+ * In essence it's a thinnish wrapper around basic SAX event
+ * <a href="../pipeline/package-summary.html">pipeline</a> facilities, which
+ * exposes only limited functionality. The <em>javax.xml.transform</em>
+ * functionality is implemented as follows: <ul>
+ *
+ * <li>The {@link javax.xml.transform.sax.SAXSource SAXSource} class
+ * just wraps an {@link XMLReader} and {@link InputSource}, while the
+ * {@link javax.xml.transform.sax.SAXResult SAXResult} class is less
+ * functional than a {@link gnu.xml.pipeline.EventConsumer EventConsumer}.
+ * (Notably, it drops all but one declaration from any DTD.)</li>
+ *
+ * <li>The {@link javax.xml.transform.dom.DOMSource DOMSource} class
+ * corresponds to special SAX parsers like {@link DomParser}, and the
+ * {@link javax.xml.transform.dom.DOMResult DOMResult} class corresponds
+ * to a {@link gnu.xml.pipeline.DomConsumer DomConsumer}.</li>
+ *
+ * <li>The {@link javax.xml.transform.stream.StreamSource StreamSource}
+ * class corresponds to a SAX {@link InputSource}, and the
+ * {@link javax.xml.transform.stream.StreamResult StreamResult} class
+ * corresponds to a {@link gnu.xml.pipeline.TextConsumer TextConsumer}.</li>
+ *
+ * </ul>
+ *
+ * <p><em>This implementation is preliminary.</em>
+ *
+ * @see gnu.xml.pipeline.XsltFilter
+ *
+ * @author David Brownell
+ */
+public class SAXNullTransformerFactory extends SAXTransformerFactory
+{
+
+ private ErrorListener errListener;
+ private URIResolver uriResolver;
+
+ /** Default constructor */
+ public SAXNullTransformerFactory () { }
+
+ //
+ // only has stuff that makes sense with null transforms
+ //
+
+ /**
+ * Returns true if the requested feature is supported.
+ * All three kinds of input and output are accepted:
+ * XML text, SAX events, and DOM nodes.
+ */
+ public boolean getFeature (String feature)
+ {
+ return SAXTransformerFactory.FEATURE.equals (feature)
+ || SAXResult.FEATURE.equals (feature)
+ || SAXSource.FEATURE.equals (feature)
+ || DOMResult.FEATURE.equals (feature)
+ || DOMSource.FEATURE.equals (feature)
+ || StreamResult.FEATURE.equals (feature)
+ || StreamSource.FEATURE.equals (feature)
+ ;
+ }
+
+ public void setFeature(String name, boolean value)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException(name);
+ }
+
+
+ /** Throws an exception (no implementation attributes are supported) */
+ public void setAttribute (String key, Object value)
+ {
+ throw new IllegalArgumentException ();
+ }
+
+ /** Throws an exception (no implementation attributes are supported) */
+ public Object getAttribute (String key)
+ {
+ throw new IllegalArgumentException ();
+ }
+
+ /** (not yet implemented) */
+ public Source getAssociatedStylesheet (Source source,
+ String media,
+ String title,
+ String charset)
+ throws TransformerConfigurationException
+ {
+ // parse, and find the appropriate xsl-stylesheet PI contents
+ throw new IllegalArgumentException ();
+ }
+
+ public Transformer newTransformer ()
+ throws TransformerConfigurationException
+ {
+ return new NullTransformer ();
+ }
+
+ /**
+ * Returns a TransformerHandler that knows how to generate output
+ * in all three standard formats. Output text is generated using
+ * {@link XMLWriter}, and the GNU implementation of
+ * {@link DomDocument DOM} is used.
+ *
+ * @see SAXResult
+ * @see StreamResult
+ * @see DOMResult
+ */
+ public TransformerHandler newTransformerHandler ()
+ throws TransformerConfigurationException
+ {
+ NullTransformer transformer = new NullTransformer ();
+ return transformer.handler;
+ }
+
+ //
+ // Stuff that depends on XSLT support, which we don't provide
+ //
+ private static final String noXSLT = "No XSLT support";
+
+ /** Throws an exception (XSLT is not supported). */
+ public Transformer newTransformer (Source stylesheet)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException (noXSLT);
+ }
+
+ /** Throws an exception (XSLT is not supported). */
+ public Templates newTemplates (Source stylesheet)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException (noXSLT);
+ }
+
+ /** Throws an exception (XSLT is not supported). */
+ public TemplatesHandler newTemplatesHandler ()
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException (noXSLT);
+ }
+
+ /** Throws an exception (XSLT is not supported). */
+ public TransformerHandler newTransformerHandler (Source stylesheet)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException (noXSLT);
+ }
+
+ /** Throws an exception (XSLT is not supported). */
+ public TransformerHandler newTransformerHandler (Templates stylesheet)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException (noXSLT);
+ }
+
+ /** Throws an exception (XSLT is not supported). */
+ public XMLFilter newXMLFilter (Source stylesheet)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException (noXSLT);
+ }
+
+ /** Throws an exception (XSLT is not supported). */
+ public XMLFilter newXMLFilter (Templates stylesheet)
+ throws TransformerConfigurationException
+ {
+ throw new TransformerConfigurationException (noXSLT);
+ }
+
+ /** Returns the value assigned by {@link #setErrorListener}. */
+ public ErrorListener getErrorListener ()
+ {
+ return errListener;
+ }
+
+ /** Assigns a value that would be used when parsing stylesheets */
+ public void setErrorListener (ErrorListener e)
+ {
+ errListener = e;
+ }
+
+ /** Returns the value assigned by {@link #setURIResolver}. */
+ public URIResolver getURIResolver ()
+ {
+ return uriResolver;
+ }
+
+ /** Assigns a value that would be used when parsing stylesheets */
+ public void setURIResolver (URIResolver u)
+ {
+ uriResolver = u;
+ }
+
+
+ //
+ // Helper classes. These might in theory be subclassed
+ // by an XSLT implementation, if they were exported.
+ //
+
+ static class DomTerminus
+ extends DomConsumer
+ {
+
+ DomTerminus (DOMResult result)
+ throws SAXException
+ {
+ // won't really throw SAXException
+ super (DomDocument.class);
+ setHandler (new DomHandler (this, result));
+ }
+
+ }
+
+ static class DomHandler
+ extends Consumer.Backdoor
+ {
+
+ private DOMResult result;
+
+ DomHandler (DomConsumer c, DOMResult r)
+ throws SAXException
+ {
+ // won't really throw SAXException
+ super (c);
+ result = r;
+ }
+
+ public void endDocument ()
+ throws SAXException
+ {
+ super.endDocument ();
+ result.setNode (getDocument ());
+ }
+
+ }
+
+ private static OutputStream getOutputStream (String uri)
+ throws IOException
+ {
+ // JDK stupidity: file "protocol does not support output" ...
+ if (uri.startsWith ("file:"))
+ return new FileOutputStream (uri.substring (5));
+
+ // Otherwise ...
+ URL url = new URL (uri);
+ URLConnection conn = url.openConnection ();
+
+ conn.setDoOutput (true);
+ return conn.getOutputStream ();
+ }
+
+
+ static class NullHandler
+ extends EventFilter
+ implements TransformerHandler
+ {
+
+ private String systemId;
+ private Transformer transformer;
+
+ NullHandler (Transformer t)
+ {
+ transformer = t;
+ }
+
+ public Transformer getTransformer ()
+ {
+ return transformer;
+ }
+
+ public String getSystemId ()
+ {
+ return systemId;
+ }
+
+ public void setSystemId (String id)
+ {
+ systemId = id;
+ }
+
+ public void setResult (Result result)
+ {
+ if (result.getSystemId () != null)
+ systemId = result.getSystemId ();
+
+ try
+ {
+
+ // output to partial SAX event stream?
+ if (result instanceof SAXResult)
+ {
+ SAXResult r = (SAXResult) result;
+
+ setContentHandler (r.getHandler ());
+ setProperty (LEXICAL_HANDLER, r.getLexicalHandler ());
+ // DTD info is filtered out by javax.transform
+
+ // output to DOM tree?
+ }
+ else if (result instanceof DOMResult)
+ {
+ DomTerminus out = new DomTerminus ((DOMResult) result);
+
+ setContentHandler (out.getContentHandler ());
+ setProperty (LEXICAL_HANDLER,
+ out.getProperty (LEXICAL_HANDLER));
+ // save DTD-derived info, if any.
+ setDTDHandler (out.getDTDHandler ());
+ setProperty (DECL_HANDLER,
+ out.getProperty (DECL_HANDLER));
+
+ // node is saved into result on endDocument()
+
+ // output to (XML) text?
+ }
+ else if (result instanceof StreamResult)
+ {
+ StreamResult r = (StreamResult) result;
+ XMLWriter out;
+
+ // FIXME: when do output properties take effect?
+ // encoding, standalone decl, xml/xhtml/... ...
+
+ // FIXME: maybe put nsfix filter up front
+
+ try
+ {
+ if (r.getWriter () != null)
+ out = new XMLWriter (r.getWriter ());
+ else if (r.getOutputStream () != null)
+ out = new XMLWriter (r.getOutputStream ());
+ else if (r.getSystemId () != null)
+ out = new XMLWriter (
+ getOutputStream (r.getSystemId ()));
+ else
+ throw new IllegalArgumentException (
+ "bad StreamResult");
+ }
+ catch (IOException e)
+ {
+ e.printStackTrace ();
+ // on jdk 1.4, pass the root cause ...
+ throw new IllegalArgumentException (e.getMessage ());
+ }
+
+ // out.setExpandingEntities (true);
+ // out.setPrettyPrinting (true);
+ // out.setXhtml (true);
+
+ setContentHandler (out);
+ setProperty (LEXICAL_HANDLER, out);
+ // save DTD info, if any; why not?
+ setDTDHandler (out);
+ setProperty (DECL_HANDLER, out);
+ }
+
+ }
+ catch (SAXException e)
+ {
+ // SAXNotSupportedException or SAXNotRecognizedException:
+ // "can't happen" ... but SAXException for DOM build probs
+ // could happen, so ...
+ // on jdk 1.4, pass the root cause ...
+ throw new IllegalArgumentException (e.getMessage ());
+ }
+ }
+ }
+
+ // an interface that adds no value
+ static class LocatorAdapter
+ extends LocatorImpl
+ implements SourceLocator
+ {
+
+ LocatorAdapter (SAXParseException e)
+ {
+ setSystemId (e.getSystemId ());
+ setPublicId (e.getPublicId ());
+ setLineNumber (e.getLineNumber ());
+ setColumnNumber (e.getColumnNumber ());
+ }
+
+ }
+
+ // another interface that adds no value
+ static class ListenerAdapter
+ implements ErrorHandler
+ {
+
+ NullTransformer transformer;
+
+ ListenerAdapter (NullTransformer t)
+ {
+ transformer = t;
+ }
+
+ private TransformerException map (SAXParseException e)
+ {
+ return new TransformerException (
+ e.getMessage (),
+ new LocatorAdapter (e),
+ e);
+ }
+
+ public void error (SAXParseException e)
+ throws SAXParseException
+ {
+ try
+ {
+ if (transformer.errListener != null)
+ transformer.errListener.error (map (e));
+ }
+ catch (TransformerException ex)
+ {
+ transformer.ex = ex;
+ throw e;
+ }
+ }
+
+ public void fatalError (SAXParseException e)
+ throws SAXParseException
+ {
+ try
+ {
+ if (transformer.errListener != null)
+ transformer.errListener.fatalError (map (e));
+ else
+ throw map (e);
+ } catch (TransformerException ex) {
+ transformer.ex = ex;
+ throw e;
+ }
+ }
+
+ public void warning (SAXParseException e)
+ throws SAXParseException
+ {
+ try
+ {
+ if (transformer.errListener != null)
+ transformer.errListener.warning (map (e));
+ }
+ catch (TransformerException ex)
+ {
+ transformer.ex = ex;
+ throw e;
+ }
+ }
+ }
+
+ static class NullTransformer
+ extends Transformer
+ {
+
+ private URIResolver uriResolver;
+ private Properties props = new Properties ();
+ private Hashtable params = new Hashtable (7);
+
+ ErrorListener errListener = null;
+ TransformerException ex = null;
+ NullHandler handler;
+
+ NullTransformer ()
+ {
+ super ();
+ handler = new NullHandler (this);
+ }
+
+ public ErrorListener getErrorListener ()
+ {
+ return errListener;
+ }
+
+ public void setErrorListener (ErrorListener e)
+ {
+ errListener = e;
+ }
+
+ public URIResolver getURIResolver ()
+ {
+ return uriResolver;
+ }
+
+ public void setURIResolver (URIResolver u)
+ {
+ uriResolver = u;
+ }
+
+ public void setOutputProperties (Properties p)
+ {
+ props = (Properties) p.clone ();
+ }
+
+ public Properties getOutputProperties ()
+ {
+ return (Properties) props.clone ();
+ }
+
+ public void setOutputProperty (String name, String value)
+ {
+ props.setProperty (name, value);
+ }
+
+ public String getOutputProperty (String name)
+ {
+ return props.getProperty (name);
+ }
+
+ public void clearParameters ()
+ {
+ params.clear ();
+ }
+
+ public void setParameter (String name, Object value)
+ {
+ props.put (name, value);
+ }
+
+ public Object getParameter (String name)
+ {
+ return props.get (name);
+ }
+
+ public void transform (Source in, Result out)
+ throws TransformerException
+ {
+ try
+ {
+ XMLReader producer;
+ InputSource input;
+
+ // Input from DOM?
+ if (in instanceof DOMSource)
+ {
+ DOMSource source = (DOMSource) in;
+
+ if (source.getNode () == null)
+ throw new IllegalArgumentException ("no DOM node");
+ producer = new DomParser (source.getNode ());
+ input = null;
+
+ // Input from SAX?
+ }
+ else if (in instanceof SAXSource)
+ {
+ SAXSource source = (SAXSource) in;
+
+ producer = source.getXMLReader ();
+ if (producer == null)
+ producer = XMLReaderFactory.createXMLReader ();
+
+ input = source.getInputSource ();
+ if (input == null)
+ {
+ if (source.getSystemId () != null)
+ input = new InputSource (source.getSystemId ());
+ else
+ throw new IllegalArgumentException (
+ "missing SAX input");
+ }
+
+ // Input from a stream or something?
+ }
+ else
+ {
+ producer = XMLReaderFactory.createXMLReader ();
+ input = SAXSource.sourceToInputSource (in);
+ if (input == null)
+ throw new IllegalArgumentException ("missing input");
+ }
+
+ // preserve original namespace prefixes
+ try
+ {
+ producer.setFeature(EventFilter.FEATURE_URI +
+ "namespace-prefixes",
+ true);
+ }
+ catch (Exception e)
+ {
+ /* ignore */
+ // FIXME if we couldn't, "NsFix" stage before the output ..
+ }
+
+ // arrange the output
+ handler.setResult (out);
+ EventFilter.bind (producer, handler);
+
+ // then parse ... single element pipeline
+ producer.parse (input);
+
+ }
+ catch (IOException e)
+ {
+ throw new TransformerException ("transform failed", e);
+
+ }
+ catch (SAXException e)
+ {
+ if (ex == null && ex.getCause () == e)
+ throw ex;
+ else
+ throw new TransformerException ("transform failed", e);
+
+ }
+ finally
+ {
+ ex = null;
+ }
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/util/XCat.java b/libjava/classpath/gnu/xml/util/XCat.java
new file mode 100644
index 000000000..ea23ad682
--- /dev/null
+++ b/libjava/classpath/gnu/xml/util/XCat.java
@@ -0,0 +1,1611 @@
+/* XCat.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.util;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.StringTokenizer;
+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.SAXNotRecognizedException;
+import org.xml.sax.SAXParseException;
+import org.xml.sax.XMLReader;
+
+import org.xml.sax.ext.DefaultHandler2;
+import org.xml.sax.ext.EntityResolver2;
+
+import org.xml.sax.helpers.XMLReaderFactory;
+
+/**
+ * Packages <a href=
+ "http://www.oasis-open.org/committees/entity/spec-2001-08-06.html"
+ >OASIS XML Catalogs</a>,
+ * primarily for entity resolution by parsers.
+ * That specification defines an XML syntax for mappings between
+ * identifiers declared in DTDs (particularly PUBLIC identifiers) and
+ * locations. SAX has always supported such mappings, but conventions for
+ * an XML file syntax to maintain them have previously been lacking.
+ *
+ * <p> This has three main operational modes. The primary intended mode is
+ * to create a resolver, then preloading it with one or more site-standard
+ * catalogs before using it with one or more SAX parsers: <pre>
+ * XCat catalog = new XCat ();
+ * catalog.setErrorHandler (diagnosticErrorHandler);
+ * catalog.loadCatalog ("file:/local/catalogs/catalog.cat");
+ * catalog.loadCatalog ("http://shared/catalog.cat");
+ * ...
+ * catalog.disableLoading ();
+ * parser1.setEntityResolver (catalog);
+ * parser2.setEntityResolver (catalog);
+ * ...</pre>
+ *
+ * <p>A second mode is to arrange that your application uses instances of
+ * this class as its entity resolver, and automatically loads catalogs
+ * referenced by <em>&lt;?oasis-xml-catalog...?&gt;</em> processing
+ * instructions found before the DTD in documents it parses.
+ * It would then discard the resolver after each parse.
+ *
+ * <p> A third mode applies catalogs in contexts other than entity
+ * resolution for parsers.
+ * The {@link #resolveURI resolveURI()} method supports resolving URIs
+ * stored in XML application data, rather than inside DTDs.
+ * Catalogs would be loaded as shown above, and the catalog could
+ * be used concurrently for parser entity resolution and for
+ * application URI resolution.
+ * </p>
+ *
+ * <center><hr width='70%'></center>
+ *
+ * <p>Errors in catalogs implicitly loaded (during resolution) are ignored
+ * beyond being reported through any <em>ErrorHandler</em> assigned using
+ * {@link #setErrorHandler setErrorHandler()}. SAX exceptions
+ * thrown from such a handler won't abort resolution, although throwing a
+ * <em>RuntimeException</em> or <em>Error</em> will normally abort both
+ * resolution and parsing. Useful diagnostic information is available to
+ * any <em>ErrorHandler</em> used to report problems, or from any exception
+ * thrown from an explicit {@link #loadCatalog loadCatalog()} invocation.
+ * Applications can use that information as troubleshooting aids.
+ *
+ * <p>While this class requires <em>SAX2 Extensions 1.1</em> classes in
+ * its class path, basic functionality does not require using a SAX2
+ * parser that supports the extended entity resolution functionality.
+ * See the original SAX1
+ * {@link #resolveEntity(java.lang.String,java.lang.String) resolveEntity()}
+ * method for a list of restrictions which apply when it is used with
+ * older SAX parsers.
+ *
+ * @see EntityResolver2
+ *
+ * @author David Brownell
+ */
+public class XCat implements EntityResolver2
+{
+ private Catalog catalogs [];
+ private boolean usingPublic = true;
+ private boolean loadingPermitted = true;
+ private boolean unified = true;
+ private String parserClass;
+ private ErrorHandler errorHandler;
+
+ // private EntityResolver next; // chain to next if we fail...
+
+ //
+ // NOTE: This is a straightforward implementation, and if
+ // there are lots of "nextCatalog" or "delegate*" entries
+ // in use, two tweaks would be worth considering:
+ //
+ // - Centralize some sort of cache (key by URI) for individual
+ // resolvers. That'd avoid multiple copies of a given catalog.
+ //
+ // - Have resolution track what catalogs (+modes) have been
+ // searched. This would support loop detection.
+ //
+
+
+ /**
+ * Initializes without preloading a catalog.
+ * This API is convenient when you may want to arrange that catalogs
+ * are automatically loaded when explicitly referenced in documents,
+ * using the <em>oasis-xml-catalog</em> processing instruction.
+ * In such cases you won't usually be able to preload catalogs.
+ */
+ public XCat () { }
+
+ /**
+ * Initializes, and preloads a catalog using the default SAX parser.
+ * This API is convenient when you operate with one or more standard
+ * catalogs.
+ *
+ * <p> This just delegates to {@link #loadCatalog loadCatalog()};
+ * see it for exception information.
+ *
+ * @param uri absolute URI for the catalog file.
+ */
+ public XCat (String uri)
+ throws SAXException, IOException
+ { loadCatalog (uri); }
+
+
+ /**
+ * Loads an OASIS XML Catalog.
+ * It is appended to the list of currently active catalogs, or
+ * reloaded if a catalog with the same URI was already loaded.
+ * Callers have control over what parser is used, how catalog parsing
+ * errors are reported, and whether URIs will be resolved consistently.
+ *
+ * <p> The OASIS specification says that errors detected when loading
+ * catalogs "must recover by ignoring the catalog entry file that
+ * failed, and proceeding." In this API, that action can be the
+ * responsibility of applications, when they explicitly load any
+ * catalog using this method.
+ *
+ * <p>Note that catalogs referenced by this one will not be loaded
+ * at this time. Catalogs referenced through <em>nextCatalog</em>
+ * or <em>delegate*</em> elements are normally loaded only if needed.
+ *
+ * @see #setErrorHandler
+ * @see #setParserClass
+ * @see #setUnified
+ *
+ * @param uri absolute URI for the catalog file.
+ *
+ * @exception IOException As thrown by the parser, typically to
+ * indicate problems reading data from that URI.
+ * @exception SAXException As thrown by the parser, typically to
+ * indicate problems parsing data from that URI. It may also
+ * be thrown if the parser doesn't support necessary handlers.
+ * @exception IllegalStateException When attempting to load a
+ * catalog after loading has been {@link #disableLoading disabled},
+ * such as after any entity or URI lookup has been performed.
+ */
+ public synchronized void loadCatalog (String uri)
+ throws SAXException, IOException
+ {
+ Catalog catalog;
+ int index = -1;
+
+ if (!loadingPermitted)
+ throw new IllegalStateException ();
+
+ uri = normalizeURI (uri);
+ if (catalogs != null) {
+ // maybe just reload
+ for (index = 0; index < catalogs.length; index++)
+ if (uri.equals (catalogs [index].catalogURI))
+ break;
+ }
+ catalog = loadCatalog (parserClass, errorHandler, uri, unified);
+
+ // add to list of catalogs
+ if (catalogs == null) {
+ index = 0;
+ catalogs = new Catalog [1];
+ } else if (index == catalogs.length) {
+ Catalog tmp [];
+
+ tmp = new Catalog [index + 1];
+ System.arraycopy (catalogs, 0, tmp, 0, index);
+ catalogs = tmp;
+ }
+ catalogs [index] = catalog;
+ }
+
+
+ /**
+ * "New Style" external entity resolution for parsers.
+ * Calls to this method prevent explicit loading of additional catalogs
+ * using {@link #loadCatalog loadCatalog()}.
+ *
+ * <p>This supports the full core catalog functionality for locating
+ * (and relocating) parsed entities that have been declared in a
+ * document's DTD.
+ *
+ * @param name Entity name, such as "dudley", "%nell", or "[dtd]".
+ * @param publicId Either a normalized public ID, or null.
+ * @param baseURI Absolute base URI associated with systemId.
+ * @param systemId URI found in entity declaration (may be
+ * relative to baseURI).
+ *
+ * @return Input source for accessing the external entity, or null
+ * if no mapping was found. The input source may have opened
+ * the stream, and will have a fully resolved URI.
+ *
+ * @see #getExternalSubset
+ */
+ public InputSource resolveEntity (
+ String name, // UNUSED ... systemId is always non-null
+ String publicId,
+ String baseURI, // UNUSED ... it just lets sysId be relative
+ String systemId
+ ) throws SAXException, IOException
+ {
+ if (loadingPermitted)
+ disableLoading ();
+
+ try {
+ // steps as found in OASIS XML catalog spec 7.1.2
+ // steps 1, 8 involve looping over the list of catalogs
+ for (int i = 0; i < catalogs.length; i++) {
+ InputSource retval;
+ retval = catalogs [i].resolve (usingPublic, publicId, systemId);
+ if (retval != null)
+ return retval;
+ }
+ } catch (DoneDelegation x) {
+ // done!
+ }
+ // step 9 involves returning "no match"
+ return null;
+ }
+
+
+ /**
+ * "New Style" parser callback to add an external subset.
+ * For documents that don't include an external subset, this may
+ * return one according to <em>doctype</em> catalog entries.
+ * (This functionality is not a core part of the OASIS XML Catalog
+ * specification, though it's presented in an appendix.)
+ * If no such entry is defined, this returns null to indicate that
+ * this document will not be modified to include such a subset.
+ * Calls to this method prevent explicit loading of additional catalogs
+ * using {@link #loadCatalog loadCatalog()}.
+ *
+ * <p><em>Warning:</em> That catalog functionality can be dangerous.
+ * It can provide definitions of general entities, and thereby mask
+ * certain well formedess errors.
+ *
+ * @param name Name of the document element, either as declared in
+ * a DOCTYPE declaration or as observed in the text.
+ * @param baseURI Document's base URI (absolute).
+ *
+ * @return Input source for accessing the external subset, or null
+ * if no mapping was found. The input source may have opened
+ * the stream, and will have a fully resolved URI.
+ */
+ public InputSource getExternalSubset (String name, String baseURI)
+ throws SAXException, IOException
+ {
+ if (loadingPermitted)
+ disableLoading ();
+ try {
+ for (int i = 0; i < catalogs.length; i++) {
+ InputSource retval = catalogs [i].getExternalSubset (name);
+ if (retval != null)
+ return retval;
+ }
+ } catch (DoneDelegation x) {
+ // done!
+ }
+ return null;
+ }
+
+
+ /**
+ * "Old Style" external entity resolution for parsers.
+ * This API provides only core functionality.
+ * Calls to this method prevent explicit loading of additional catalogs
+ * using {@link #loadCatalog loadCatalog()}.
+ *
+ * <p>The functional limitations of this interface include:</p><ul>
+ *
+ * <li>Since system IDs will be absolutized before the resolver
+ * sees them, matching against relative URIs won't work.
+ * This may affect <em>system</em>, <em>rewriteSystem</em>,
+ * and <em>delegateSystem</em> catalog entries.
+ *
+ * <li>Because of that absolutization, documents declaring entities
+ * with system IDs using URI schemes that the JVM does not recognize
+ * may be unparsable. URI schemes such as <em>file:/</em>,
+ * <em>http://</em>, <em>https://</em>, and <em>ftp://</em>
+ * will usually work reliably.
+ *
+ * <li>Because missing external subsets can't be provided, the
+ * <em>doctype</em> catalog entries will be ignored.
+ * (The {@link #getExternalSubset getExternalSubset()} method is
+ * a "New Style" resolution option.)
+ *
+ * </ul>
+ *
+ * <p>Applications can tell whether this limited functionality will be
+ * used: if the feature flag associated with the {@link EntityResolver2}
+ * interface is not <em>true</em>, the limitations apply. Applications
+ * can't usually know whether a given document and catalog will trigger
+ * those limitations. The issue can only be bypassed by operational
+ * procedures such as not using catalogs or documents which involve
+ * those features.
+ *
+ * @param publicId Either a normalized public ID, or null
+ * @param systemId Always an absolute URI.
+ *
+ * @return Input source for accessing the external entity, or null
+ * if no mapping was found. The input source may have opened
+ * the stream, and will have a fully resolved URI.
+ */
+ final public InputSource resolveEntity (String publicId, String systemId)
+ throws SAXException, IOException
+ {
+ return resolveEntity (null, publicId, null, systemId);
+ }
+
+
+ /**
+ * Resolves a URI reference that's not defined to the DTD.
+ * This is intended for use with URIs found in document text, such as
+ * <em>xml-stylesheet</em> processing instructions and in attribute
+ * values, where they are not recognized as URIs by XML parsers.
+ * Calls to this method prevent explicit loading of additional catalogs
+ * using {@link #loadCatalog loadCatalog()}.
+ *
+ * <p>This functionality is supported by the OASIS XML Catalog
+ * specification, but will never be invoked by an XML parser.
+ * It corresponds closely to functionality for mapping system
+ * identifiers for entities declared in DTDs; closely enough that
+ * this implementation's default behavior is that they be
+ * identical, to minimize potential confusion.
+ *
+ * <p>This method could be useful when implementing the
+ * {@link javax.xml.transform.URIResolver} interface, wrapping the
+ * input source in a {@link javax.xml.transform.sax.SAXSource}.
+ *
+ * @see #isUnified
+ * @see #setUnified
+ *
+ * @param baseURI The relevant base URI as specified by the XML Base
+ * specification. This recognizes <em>xml:base</em> attributes
+ * as overriding the actual (physical) base URI.
+ * @param uri Either an absolute URI, or one relative to baseURI
+ *
+ * @return Input source for accessing the mapped URI, or null
+ * if no mapping was found. The input source may have opened
+ * the stream, and will have a fully resolved URI.
+ */
+ public InputSource resolveURI (String baseURI, String uri)
+ throws SAXException, IOException
+ {
+ if (loadingPermitted)
+ disableLoading ();
+
+ // NOTE: baseURI isn't used here, but caller MUST have it,
+ // and heuristics _might_ use it in the future ... plus,
+ // it's symmetric with resolveEntity ().
+
+ // steps 1, 6 involve looping
+ try {
+ for (int i = 0; i < catalogs.length; i++) {
+ InputSource tmp = catalogs [i].resolveURI (uri);
+ if (tmp != null)
+ return tmp;
+ }
+ } catch (DoneDelegation x) {
+ // done
+ }
+ // step 7 reports no match
+ return null;
+ }
+
+
+ /**
+ * Records that catalog loading is no longer permitted.
+ * Loading is automatically disabled when lookups are performed,
+ * and should be manually disabled when <em>startDTD()</em> (or
+ * any other DTD declaration callback) is invoked, or at the latest
+ * when the document root element is seen.
+ */
+ public synchronized void disableLoading ()
+ {
+ // NOTE: this method and loadCatalog() are synchronized
+ // so that it's impossible to load (top level) catalogs
+ // after lookups start. Likewise, deferred loading is also
+ // synchronized (for "next" and delegated catalogs) to
+ // ensure that parsers can share resolvers.
+ loadingPermitted = false;
+ }
+
+
+ /**
+ * Returns the error handler used to report catalog errors.
+ * Null is returned if the parser's default error handling
+ * will be used.
+ *
+ * @see #setErrorHandler
+ */
+ public ErrorHandler getErrorHandler ()
+ { return errorHandler; }
+
+ /**
+ * Assigns the error handler used to report catalog errors.
+ * These errors may come either from the SAX2 parser or
+ * from the catalog parsing code driven by the parser.
+ *
+ * <p> If you're sharing the resolver between parsers, don't
+ * change this once lookups have begun.
+ *
+ * @see #getErrorHandler
+ *
+ * @param parser The error handler, or null saying to use the default
+ * (no diagnostics, and only fatal errors terminate loading).
+ */
+ public void setErrorHandler (ErrorHandler handler)
+ { errorHandler = handler; }
+
+
+ /**
+ * Returns the name of the SAX2 parser class used to parse catalogs.
+ * Null is returned if the system default is used.
+ * @see #setParserClass
+ */
+ public String getParserClass ()
+ { return parserClass; }
+
+ /**
+ * Names the SAX2 parser class used to parse catalogs.
+ *
+ * <p> If you're sharing the resolver between parsers, don't change
+ * this once lookups have begun.
+ *
+ * <p> Note that in order to properly support the <em>xml:base</em>
+ * attribute and relative URI resolution, the SAX parser used to parse
+ * the catalog must provide a {@link Locator} and support the optional
+ * declaration and lexical handlers.
+ *
+ * @see #getParserClass
+ *
+ * @param parser The parser class name, or null saying to use the
+ * system default SAX2 parser.
+ */
+ public void setParserClass (String parser)
+ { parserClass = parser; }
+
+
+ /**
+ * Returns true (the default) if all methods resolve
+ * a given URI in the same way.
+ * Returns false if calls resolving URIs as entities (such as
+ * {@link #resolveEntity resolveEntity()}) use different catalog entries
+ * than those resolving them as URIs ({@link #resolveURI resolveURI()}),
+ * which will generally produce different results.
+ *
+ * <p>The OASIS XML Catalog specification defines two related schemes
+ * to map URIs "as URIs" or "as system IDs".
+ * URIs use <em>uri</em>, <em>rewriteURI</em>, and <em>delegateURI</em>
+ * elements. System IDs do the same things with <em>systemId</em>,
+ * <em>rewriteSystemId</em>, and <em>delegateSystemId</em>.
+ * It's confusing and error prone to maintain two parallel copies of
+ * such data. Accordingly, this class makes that behavior optional.
+ * The <em>unified</em> interpretation of URI mappings is preferred,
+ * since it prevents surprises where one URI gets mapped to different
+ * contents depending on whether the reference happens to have come
+ * from a DTD (or not).
+ *
+ * @see #setUnified
+ */
+ public boolean isUnified ()
+ { return unified; }
+
+ /**
+ * Assigns the value of the flag returned by {@link #isUnified}.
+ * Set it to false to be strictly conformant with the OASIS XML Catalog
+ * specification. Set it to true to make all mappings for a given URI
+ * give the same result, regardless of the reason for the mapping.
+ *
+ * <p>Don't change this once you've loaded the first catalog.
+ *
+ * @param value new flag setting
+ */
+ public void setUnified (boolean value)
+ { unified = value; }
+
+
+ /**
+ * Returns true (the default) if a catalog's public identifier
+ * mappings will be used.
+ * When false is returned, such mappings are ignored except when
+ * system IDs are discarded, such as for
+ * entities using the <em>urn:publicid:</em> URI scheme in their
+ * system identifiers. (See RFC 3151 for information about that
+ * URI scheme. Using it in system identifiers may not work well
+ * with many SAX parsers unless the <em>resolve-dtd-uris</em>
+ * feature flag is set to false.)
+ * @see #setUsingPublic
+ */
+ public boolean isUsingPublic ()
+ { return usingPublic; }
+
+ /**
+ * Specifies which catalog search mode is used.
+ * By default, public identifier mappings are able to override system
+ * identifiers when both are available.
+ * Applications may choose to ignore public
+ * identifier mappings in such cases, so that system identifiers
+ * declared in DTDs will only be overridden by an explicit catalog
+ * match for that system ID.
+ *
+ * <p> If you're sharing the resolver between parsers, don't
+ * change this once lookups have begun.
+ * @see #isUsingPublic
+ *
+ * @param value true to always use public identifier mappings,
+ * false to only use them for system ids using the <em>urn:publicid:</em>
+ * URI scheme.
+ */
+ public void setUsingPublic (boolean value)
+ { usingPublic = value; }
+
+
+
+ // hmm, what's this do? :)
+ private static Catalog loadCatalog (
+ String parserClass,
+ ErrorHandler eh,
+ String uri,
+ boolean unified
+ ) throws SAXException, IOException
+ {
+ XMLReader parser;
+ Loader loader;
+ boolean doesIntern = false;
+
+ if (parserClass == null)
+ parser = XMLReaderFactory.createXMLReader ();
+ else
+ parser = XMLReaderFactory.createXMLReader (parserClass);
+ if (eh != null)
+ parser.setErrorHandler (eh);
+ // resolve-dtd-entities is at default value (unrecognized == true)
+
+ try {
+ doesIntern = parser.getFeature (
+ "http://xml.org/sax/features/string-interning");
+ } catch (SAXNotRecognizedException e) { }
+
+ loader = new Loader (doesIntern, eh, unified);
+ loader.cat.parserClass = parserClass;
+ loader.cat.catalogURI = uri;
+
+ parser.setContentHandler (loader);
+ parser.setProperty (
+ "http://xml.org/sax/properties/declaration-handler",
+ loader);
+ parser.setProperty (
+ "http://xml.org/sax/properties/lexical-handler",
+ loader);
+ parser.parse (uri);
+
+ return loader.cat;
+ }
+
+ // perform one or both the normalizations for public ids
+ private static String normalizePublicId (boolean full, String publicId)
+ {
+ if (publicId.startsWith ("urn:publicid:")) {
+ CPStringBuilder buf = new CPStringBuilder ();
+ char chars [] = publicId.toCharArray ();
+boolean hasbug = false;
+
+ for (int i = 13; i < chars.length; i++) {
+ switch (chars [i]) {
+ case '+': buf.append (' '); continue;
+ case ':': buf.append ("//"); continue;
+ case ';': buf.append ("::"); continue;
+ case '%':
+// FIXME unhex that char! meanwhile, warn and fallthrough ...
+ hasbug = true;
+ default: buf.append (chars [i]); continue;
+ }
+ }
+ publicId = buf.toString ();
+if (hasbug)
+System.err.println ("nyet unhexing public id: " + publicId);
+ full = true;
+ }
+
+ // SAX parsers do everything except that URN mapping, but
+ // we can't trust other sources to normalize correctly
+ if (full) {
+ StringTokenizer tokens;
+ String token;
+
+ tokens = new StringTokenizer (publicId, " \r\n");
+ publicId = null;
+ while (tokens.hasMoreTokens ()) {
+ if (publicId == null)
+ publicId = tokens.nextToken ();
+ else
+ publicId += " " + tokens.nextToken ();
+ }
+ }
+ return publicId;
+ }
+
+ private static boolean isUriExcluded (int c)
+ { return c <= 0x20 || c >= 0x7f || "\"<>^`{|}".indexOf (c) != -1; }
+
+ private static int hexNibble (int c)
+ {
+ if (c < 10)
+ return c + '0';
+ return ('a' - 10) + c;
+ }
+
+ // handles URIs with "excluded" characters
+ private static String normalizeURI (String systemId)
+ {
+ int length = systemId.length ();
+
+ for (int i = 0; i < length; i++) {
+ char c = systemId.charAt (i);
+
+ // escape non-ASCII plus "excluded" characters
+ if (isUriExcluded (c)) {
+ byte buf [];
+ ByteArrayOutputStream out;
+ int b;
+
+ // a JVM that doesn't know UTF8 and 8859_1 is unusable!
+ try {
+ buf = systemId.getBytes ("UTF8");
+ out = new ByteArrayOutputStream (buf.length + 10);
+
+ for (i = 0; i < buf.length; i++) {
+ b = buf [i] & 0x0ff;
+ if (isUriExcluded (b)) {
+ out.write ((int) '%');
+ out.write (hexNibble (b >> 4));
+ out.write (hexNibble (b & 0x0f));
+ } else
+ out.write (b);
+ }
+ return out.toString ("8859_1");
+ } catch (IOException e) {
+ throw new RuntimeException (
+ "can't normalize URI: " + e.getMessage ());
+ }
+ }
+ }
+ return systemId;
+ }
+
+ // thrown to mark authoritative end of a search
+ private static class DoneDelegation extends SAXException
+ {
+ DoneDelegation () { }
+ }
+
+
+ /**
+ * Represents a OASIS XML Catalog, and encapsulates much of
+ * the catalog functionality.
+ */
+ private static class Catalog
+ {
+ // loading infrastructure
+ String catalogURI;
+ ErrorHandler eh;
+ boolean unified;
+ String parserClass;
+
+ // catalog data
+ boolean hasPreference;
+ boolean usingPublic;
+
+ Hashtable publicIds;
+ Hashtable publicDelegations;
+
+ Hashtable systemIds;
+ Hashtable systemRewrites;
+ Hashtable systemDelegations;
+
+ Hashtable uris;
+ Hashtable uriRewrites;
+ Hashtable uriDelegations;
+
+ Hashtable doctypes;
+
+ Vector next;
+
+ // nonpublic!
+ Catalog () { }
+
+
+ // steps as found in OASIS XML catalog spec 7.1.2
+ private InputSource locatePublicId (String publicId)
+ throws SAXException, IOException
+ {
+ // 5. return (first) 'public' entry
+ if (publicIds != null) {
+ String retval = (String) publicIds.get (publicId);
+ if (retval != null) {
+ // IF the URI is accessible ...
+ return new InputSource (retval);
+ }
+ }
+
+ // 6. return delegatePublic catalog match [complex]
+ if (publicDelegations != null)
+ return checkDelegations (publicDelegations, publicId,
+ publicId, null);
+
+ return null;
+ }
+
+ // steps as found in OASIS XML catalog spec 7.1.2 or 7.2.2
+ private InputSource mapURI (
+ String uri,
+ Hashtable ids,
+ Hashtable rewrites,
+ Hashtable delegations
+ ) throws SAXException, IOException
+ {
+ // 7.1.2: 2. return (first) 'system' entry
+ // 7.2.2: 2. return (first) 'uri' entry
+ if (ids != null) {
+ String retval = (String) ids.get (uri);
+ if (retval != null) {
+ // IF the URI is accessible ...
+ return new InputSource (retval);
+ }
+ }
+
+ // 7.1.2: 3. return 'rewriteSystem' entries
+ // 7.2.2: 3. return 'rewriteURI' entries
+ if (rewrites != null) {
+ String prefix = null;
+ String replace = null;
+ int prefixLen = -1;
+
+ for (Enumeration e = rewrites.keys ();
+ e.hasMoreElements ();
+ /* NOP */) {
+ String temp = (String) e.nextElement ();
+ int len = -1;
+
+ if (!uri.startsWith (temp))
+ continue;
+ if (prefix != null
+ && (len = temp.length ()) < prefixLen)
+ continue;
+ prefix = temp;
+ prefixLen = len;
+ replace = (String) rewrites.get (temp);
+ }
+ if (prefix != null) {
+ CPStringBuilder buf = new CPStringBuilder (replace);
+ buf.append (uri.substring (prefixLen));
+ // IF the URI is accessible ...
+ return new InputSource (buf.toString ());
+ }
+ }
+
+ // 7.1.2: 4. return 'delegateSystem' catalog match [complex]
+ // 7.2.2: 4. return 'delegateURI' catalog match [complex]
+ if (delegations != null)
+ return checkDelegations (delegations, uri, null, uri);
+
+ return null;
+ }
+
+
+ /**
+ * Returns a URI for an external entity.
+ */
+ public InputSource resolve (
+ boolean usingPublic,
+ String publicId,
+ String systemId
+ ) throws SAXException, IOException
+ {
+ boolean preferSystem;
+ InputSource retval;
+
+ if (hasPreference)
+ preferSystem = !this.usingPublic;
+ else
+ preferSystem = !usingPublic;
+
+ if (publicId != null)
+ publicId = normalizePublicId (false, publicId);
+
+ // behavior here matches section 7.1.1 of the oasis spec
+ if (systemId != null) {
+ if (systemId.startsWith ("urn:publicid:")) {
+ String temp = normalizePublicId (true, systemId);
+ if (publicId == null) {
+ publicId = temp;
+ systemId = null;
+ } else if (!publicId.equals (temp)) {
+ // error; ok to recover by:
+ systemId = null;
+ }
+ } else
+ systemId = normalizeURI (systemId);
+ }
+
+ if (systemId == null && publicId == null)
+ return null;
+
+ if (systemId != null) {
+ retval = mapURI (systemId, systemIds, systemRewrites,
+ systemDelegations);
+ if (retval != null) {
+ retval.setPublicId (publicId);
+ return retval;
+ }
+ }
+
+ if (publicId != null
+ && !(systemId != null && preferSystem)) {
+ retval = locatePublicId (publicId);
+ if (retval != null) {
+ retval.setPublicId (publicId);
+ return retval;
+ }
+ }
+
+ // 7. apply nextCatalog entries
+ if (next != null) {
+ int length = next.size ();
+ for (int i = 0; i < length; i++) {
+ Catalog n = getNext (i);
+ retval = n.resolve (usingPublic, publicId, systemId);
+ if (retval != null)
+ return retval;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Maps one URI into another, for resources that are not defined
+ * using XML external entity or notation syntax.
+ */
+ public InputSource resolveURI (String uri)
+ throws SAXException, IOException
+ {
+ if (uri.startsWith ("urn:publicid:"))
+ return resolve (true, normalizePublicId (true, uri), null);
+
+ InputSource retval;
+
+ uri = normalizeURI (uri);
+
+ // 7.2.2 steps 2-4
+ retval = mapURI (uri, uris, uriRewrites, uriDelegations);
+ if (retval != null)
+ return retval;
+
+ // 7.2.2 step 5. apply nextCatalog entries
+ if (next != null) {
+ int length = next.size ();
+ for (int i = 0; i < length; i++) {
+ Catalog n = getNext (i);
+ retval = n.resolveURI (uri);
+ if (retval != null)
+ return retval;
+ }
+ }
+
+ return null;
+ }
+
+
+ /**
+ * Finds the external subset associated with a given root element.
+ */
+ public InputSource getExternalSubset (String name)
+ throws SAXException, IOException
+ {
+ if (doctypes != null) {
+ String value = (String) doctypes.get (name);
+ if (value != null) {
+ // IF the URI is accessible ...
+ return new InputSource (value);
+ }
+ }
+ if (next != null) {
+ int length = next.size ();
+ for (int i = 0; i < length; i++) {
+ Catalog n = getNext (i);
+ if (n == null)
+ continue;
+ InputSource retval = n.getExternalSubset (name);
+ if (retval != null)
+ return retval;
+ }
+ }
+ return null;
+ }
+
+ private synchronized Catalog getNext (int i)
+ throws SAXException, IOException
+ {
+ Object obj;
+
+ if (next == null || i < 0 || i >= next.size ())
+ return null;
+ obj = next.elementAt (i);
+ if (obj instanceof Catalog)
+ return (Catalog) obj;
+
+ // ok, we deferred reading that catalog till now.
+ // load and cache it.
+ Catalog cat = null;
+
+ try {
+ cat = loadCatalog (parserClass, eh, (String) obj, unified);
+ next.setElementAt (cat, i);
+ } catch (SAXException e) {
+ // must fail quietly, says the OASIS spec
+ } catch (IOException e) {
+ // same applies here
+ }
+ return cat;
+ }
+
+ private InputSource checkDelegations (
+ Hashtable delegations,
+ String id,
+ String publicId, // only one of public/system
+ String systemId // will be non-null...
+ ) throws SAXException, IOException
+ {
+ Vector matches = null;
+ int length = 0;
+
+ // first, see if any prefixes match.
+ for (Enumeration e = delegations.keys ();
+ e.hasMoreElements ();
+ /* NOP */) {
+ String prefix = (String) e.nextElement ();
+
+ if (!id.startsWith (prefix))
+ continue;
+ if (matches == null)
+ matches = new Vector ();
+
+ // maintain in longer->shorter sorted order
+ // NOTE: assumes not many matches will fire!
+ int index;
+
+ for (index = 0; index < length; index++) {
+ String temp = (String) matches.elementAt (index);
+ if (prefix.length () > temp.length ()) {
+ matches.insertElementAt (prefix, index);
+ break;
+ }
+ }
+ if (index == length)
+ matches.addElement (prefix);
+ length++;
+ }
+ if (matches == null)
+ return null;
+
+ // now we know the list of catalogs to replace our "top level"
+ // list ... we use it here, rather than somehow going back and
+ // restarting, since this helps avoid reading most catalogs.
+ // this assumes stackspace won't be a problem.
+ for (int i = 0; i < length; i++) {
+ Catalog catalog = null;
+ InputSource result;
+
+ // get this catalog. we may not have read it yet.
+ synchronized (delegations) {
+ Object prefix = matches.elementAt (i);
+ Object cat = delegations.get (prefix);
+
+ if (cat instanceof Catalog)
+ catalog = (Catalog) cat;
+ else {
+ try {
+ // load and cache that catalog
+ catalog = loadCatalog (parserClass, eh,
+ (String) cat, unified);
+ delegations.put (prefix, catalog);
+ } catch (SAXException e) {
+ // must ignore, says the OASIS spec
+ } catch (IOException e) {
+ // same applies here
+ }
+ }
+ }
+
+ // ignore failed loads, and proceed
+ if (catalog == null)
+ continue;
+
+ // we have a catalog ... resolve!
+ // usingPublic value can't matter, there's no choice
+ result = catalog.resolve (true, publicId, systemId);
+ if (result != null)
+ return result;
+ }
+
+ // if there were no successes, the entire
+ // lookup failed (all the way to top level)
+ throw new DoneDelegation ();
+ }
+ }
+
+
+ /** This is the namespace URI used for OASIS XML Catalogs. */
+ private static final String catalogNamespace =
+ "urn:oasis:names:tc:entity:xmlns:xml:catalog";
+
+
+ /**
+ * Loads/unmarshals one catalog.
+ */
+ private static class Loader extends DefaultHandler2
+ {
+ private boolean preInterned;
+ private ErrorHandler handler;
+ private boolean unified;
+ private int ignoreDepth;
+ private Locator locator;
+ private boolean started;
+ private Hashtable externals;
+ private Stack bases;
+
+ Catalog cat = new Catalog ();
+
+
+ /**
+ * Constructor.
+ * @param flag true iff the parser already interns strings.
+ * @param eh Errors and warnings are delegated to this.
+ * @param unified true keeps one table for URI mappings;
+ * false matches OASIS spec, storing mappings
+ * for URIs and SYSTEM ids in parallel tables.
+ */
+ Loader (boolean flag, ErrorHandler eh, boolean unified)
+ {
+ preInterned = flag;
+ handler = eh;
+ this.unified = unified;
+ cat.unified = unified;
+ cat.eh = eh;
+ }
+
+
+ // strips out fragments
+ private String nofrag (String uri)
+ throws SAXException
+ {
+ if (uri.indexOf ('#') != -1) {
+ warn ("URI with fragment: " + uri);
+ uri = uri.substring (0, uri.indexOf ('#'));
+ }
+ return uri;
+ }
+
+ // absolutizes relative URIs
+ private String absolutize (String uri)
+ throws SAXException
+ {
+ // avoid creating URLs if they're already absolutized,
+ // or if the URI is already using a known scheme
+ if (uri.startsWith ("file:/")
+ || uri.startsWith ("http:/")
+ || uri.startsWith ("https:/")
+ || uri.startsWith ("ftp:/")
+ || uri.startsWith ("urn:")
+ )
+ return uri;
+
+ // otherwise, let's hope the JDK handles this URI scheme.
+ try {
+ URL base = (URL) bases.peek ();
+ return new URL (base, uri).toString ();
+ } catch (Exception e) {
+ fatal ("can't absolutize URI: " + uri);
+ return null;
+ }
+ }
+
+ // recoverable error
+ private void error (String message)
+ throws SAXException
+ {
+ if (handler == null)
+ return;
+ handler.error (new SAXParseException (message, locator));
+ }
+
+ // nonrecoverable error
+ private void fatal (String message)
+ throws SAXException
+ {
+ SAXParseException spe;
+
+ spe = new SAXParseException (message, locator);
+ if (handler != null)
+ handler.fatalError (spe);
+ throw spe;
+ }
+
+ // low severity problem
+ private void warn (String message)
+ throws SAXException
+ {
+ if (handler == null)
+ return;
+ handler.warning (new SAXParseException (message, locator));
+ }
+
+ // callbacks:
+
+ public void setDocumentLocator (Locator l)
+ { locator = l; }
+
+ public void startDocument ()
+ throws SAXException
+ {
+ if (locator == null)
+ error ("no locator!");
+ bases = new Stack ();
+ String uri = locator.getSystemId ();
+ try {
+ bases.push (new URL (uri));
+ } catch (IOException e) {
+ fatal ("bad document base URI: " + uri);
+ }
+ }
+
+ public void endDocument ()
+ throws SAXException
+ {
+ try {
+ if (!started)
+ error ("not a catalog!");
+ } finally {
+ locator = null;
+ handler = null;
+ externals = null;
+ bases = null;
+ }
+ }
+
+ // XML Base support for external entities.
+
+ // NOTE: expects parser is in default "resolve-dtd-uris" mode.
+ public void externalEntityDecl (String name, String pub, String sys)
+ throws SAXException
+ {
+ if (externals == null)
+ externals = new Hashtable ();
+ if (externals.get (name) == null)
+ externals.put (name, pub);
+ }
+
+ public void startEntity (String name)
+ throws SAXException
+ {
+ if (externals == null)
+ return;
+ String uri = (String) externals.get (name);
+
+ // NOTE: breaks if an EntityResolver substitutes these URIs.
+ // If toplevel loader supports one, must intercept calls...
+ if (uri != null) {
+ try {
+ bases.push (new URL (uri));
+ } catch (IOException e) {
+ fatal ("entity '" + name + "', bad URI: " + uri);
+ }
+ }
+ }
+
+ public void endEntity (String name)
+ {
+ if (externals == null)
+ return;
+ String value = (String) externals.get (name);
+
+ if (value != null)
+ bases.pop ();
+ }
+
+ /**
+ * Processes catalog elements, saving their data.
+ */
+ public void startElement (String namespace, String local,
+ String qName, Attributes atts)
+ throws SAXException
+ {
+ // must ignore non-catalog elements, and their contents
+ if (ignoreDepth != 0 || !catalogNamespace.equals (namespace)) {
+ ignoreDepth++;
+ return;
+ }
+
+ // basic sanity checks
+ if (!preInterned)
+ local = local.intern ();
+ if (!started) {
+ started = true;
+ if ("catalog" != local)
+ fatal ("root element not 'catalog': " + local);
+ }
+
+ // Handle any xml:base attribute
+ String xmlbase = atts.getValue ("xml:base");
+
+ if (xmlbase != null) {
+ URL base = (URL) bases.peek ();
+ try {
+ base = new URL (base, xmlbase);
+ } catch (IOException e) {
+ fatal ("can't resolve xml:base attribute: " + xmlbase);
+ }
+ bases.push (base);
+ } else
+ bases.push (bases.peek ());
+
+ // fetch multi-element attributes, apply standard tweaks
+ // values (uri, catalog, rewritePrefix) get normalized too,
+ // as a precaution and since we may compare the values
+ String catalog = atts.getValue ("catalog");
+ if (catalog != null)
+ catalog = normalizeURI (absolutize (catalog));
+
+ String rewritePrefix = atts.getValue ("rewritePrefix");
+ if (rewritePrefix != null)
+ rewritePrefix = normalizeURI (absolutize (rewritePrefix));
+
+ String systemIdStartString;
+ systemIdStartString = atts.getValue ("systemIdStartString");
+ if (systemIdStartString != null) {
+ systemIdStartString = normalizeURI (systemIdStartString);
+ // unmatchable <rewriteSystemId>, <delegateSystemId> elements
+ if (systemIdStartString.startsWith ("urn:publicid:")) {
+ error ("systemIdStartString is really a publicId!!");
+ return;
+ }
+ }
+
+ String uri = atts.getValue ("uri");
+ if (uri != null)
+ uri = normalizeURI (absolutize (uri));
+
+ String uriStartString;
+ uriStartString = atts.getValue ("uriStartString");
+ if (uriStartString != null) {
+ uriStartString = normalizeURI (uriStartString);
+ // unmatchable <rewriteURI>, <delegateURI> elements
+ if (uriStartString.startsWith ("urn:publicid:")) {
+ error ("uriStartString is really a publicId!!");
+ return;
+ }
+ }
+
+ // strictly speaking "group" and "catalog" shouldn't nest
+ // ... arbitrary restriction, no evident motivation
+
+// FIXME stack "prefer" settings (two elements only!) and use
+// them to populate different public mapping/delegation tables
+
+ if ("catalog" == local || "group" == local) {
+ String prefer = atts.getValue ("prefer");
+
+ if (prefer != null && !"public".equals (prefer)) {
+ if (!"system".equals (prefer)) {
+ error ("in <" + local + " ... prefer='...'>, "
+ + "assuming 'public'");
+ prefer = "public";
+ }
+ }
+ if (prefer != null) {
+ if ("catalog" == local) {
+ cat.hasPreference = true;
+ cat.usingPublic = "public".equals (prefer);
+ } else {
+ if (!cat.hasPreference || cat.usingPublic
+ != "public".equals (prefer)) {
+fatal ("<group prefer=...> case not handled");
+ }
+ }
+ } else if ("group" == local && cat.hasPreference) {
+fatal ("<group prefer=...> case not handled");
+ }
+
+ //
+ // PUBLIC ids: cleanly set up for id substitution
+ //
+ } else if ("public" == local) {
+ String publicId = atts.getValue ("publicId");
+ String value = null;
+
+ if (publicId == null || uri == null) {
+ error ("expecting <public publicId=... uri=.../>");
+ return;
+ }
+ publicId = normalizePublicId (true, publicId);
+ uri = nofrag (uri);
+ if (cat.publicIds == null)
+ cat.publicIds = new Hashtable ();
+ else
+ value = (String) cat.publicIds.get (publicId);
+ if (value != null) {
+ if (!value.equals (uri))
+ warn ("ignoring <public...> entry for " + publicId);
+ } else
+ cat.publicIds.put (publicId, uri);
+
+ } else if ("delegatePublic" == local) {
+ String publicIdStartString;
+ Object value = null;
+
+ publicIdStartString = atts.getValue ("publicIdStartString");
+ if (publicIdStartString == null || catalog == null) {
+ error ("expecting <delegatePublic "
+ + "publicIdStartString=... catalog=.../>");
+ return;
+ }
+ publicIdStartString = normalizePublicId (true,
+ publicIdStartString);
+ if (cat.publicDelegations == null)
+ cat.publicDelegations = new Hashtable ();
+ else
+ value = cat.publicDelegations.get (publicIdStartString);
+ if (value != null) {
+ if (!value.equals (catalog))
+ warn ("ignoring <delegatePublic...> entry for "
+ + uriStartString);
+ } else
+ cat.publicDelegations.put (publicIdStartString, catalog);
+
+
+ //
+ // SYSTEM ids: need substitution due to operational issues
+ //
+ } else if ("system" == local) {
+ String systemId = atts.getValue ("systemId");
+ String value = null;
+
+ if (systemId == null || uri == null) {
+ error ("expecting <system systemId=... uri=.../>");
+ return;
+ }
+ systemId = normalizeURI (systemId);
+ uri = nofrag (uri);
+ if (systemId.startsWith ("urn:publicid:")) {
+ error ("systemId is really a publicId!!");
+ return;
+ }
+ if (cat.systemIds == null) {
+ cat.systemIds = new Hashtable ();
+ if (unified)
+ cat.uris = cat.systemIds;
+ } else
+ value = (String) cat.systemIds.get (systemId);
+ if (value != null) {
+ if (!value.equals (uri))
+ warn ("ignoring <system...> entry for " + systemId);
+ } else
+ cat.systemIds.put (systemId, uri);
+
+ } else if ("rewriteSystem" == local) {
+ String value = null;
+
+ if (systemIdStartString == null || rewritePrefix == null
+ || systemIdStartString.length () == 0
+ || rewritePrefix.length () == 0
+ ) {
+ error ("expecting <rewriteSystem "
+ + "systemIdStartString=... rewritePrefix=.../>");
+ return;
+ }
+ if (cat.systemRewrites == null) {
+ cat.systemRewrites = new Hashtable ();
+ if (unified)
+ cat.uriRewrites = cat.systemRewrites;
+ } else
+ value = (String) cat.systemRewrites.get (
+ systemIdStartString);
+ if (value != null) {
+ if (!value.equals (rewritePrefix))
+ warn ("ignoring <rewriteSystem...> entry for "
+ + systemIdStartString);
+ } else
+ cat.systemRewrites.put (systemIdStartString,
+ rewritePrefix);
+
+ } else if ("delegateSystem" == local) {
+ Object value = null;
+
+ if (systemIdStartString == null || catalog == null) {
+ error ("expecting <delegateSystem "
+ + "systemIdStartString=... catalog=.../>");
+ return;
+ }
+ if (cat.systemDelegations == null) {
+ cat.systemDelegations = new Hashtable ();
+ if (unified)
+ cat.uriDelegations = cat.systemDelegations;
+ } else
+ value = cat.systemDelegations.get (systemIdStartString);
+ if (value != null) {
+ if (!value.equals (catalog))
+ warn ("ignoring <delegateSystem...> entry for "
+ + uriStartString);
+ } else
+ cat.systemDelegations.put (systemIdStartString, catalog);
+
+
+ //
+ // URI: just like "system" ID support, except that
+ // fragment IDs are disallowed in "system" elements.
+ //
+ } else if ("uri" == local) {
+ String name = atts.getValue ("name");
+ String value = null;
+
+ if (name == null || uri == null) {
+ error ("expecting <uri name=... uri=.../>");
+ return;
+ }
+ if (name.startsWith ("urn:publicid:")) {
+ error ("name is really a publicId!!");
+ return;
+ }
+ name = normalizeURI (name);
+ if (cat.uris == null) {
+ cat.uris = new Hashtable ();
+ if (unified)
+ cat.systemIds = cat.uris;
+ } else
+ value = (String) cat.uris.get (name);
+ if (value != null) {
+ if (!value.equals (uri))
+ warn ("ignoring <uri...> entry for " + name);
+ } else
+ cat.uris.put (name, uri);
+
+ } else if ("rewriteURI" == local) {
+ String value = null;
+
+ if (uriStartString == null || rewritePrefix == null
+ || uriStartString.length () == 0
+ || rewritePrefix.length () == 0
+ ) {
+ error ("expecting <rewriteURI "
+ + "uriStartString=... rewritePrefix=.../>");
+ return;
+ }
+ if (cat.uriRewrites == null) {
+ cat.uriRewrites = new Hashtable ();
+ if (unified)
+ cat.systemRewrites = cat.uriRewrites;
+ } else
+ value = (String) cat.uriRewrites.get (uriStartString);
+ if (value != null) {
+ if (!value.equals (rewritePrefix))
+ warn ("ignoring <rewriteURI...> entry for "
+ + uriStartString);
+ } else
+ cat.uriRewrites.put (uriStartString, rewritePrefix);
+
+ } else if ("delegateURI" == local) {
+ Object value = null;
+
+ if (uriStartString == null || catalog == null) {
+ error ("expecting <delegateURI "
+ + "uriStartString=... catalog=.../>");
+ return;
+ }
+ if (cat.uriDelegations == null) {
+ cat.uriDelegations = new Hashtable ();
+ if (unified)
+ cat.systemDelegations = cat.uriDelegations;
+ } else
+ value = cat.uriDelegations.get (uriStartString);
+ if (value != null) {
+ if (!value.equals (catalog))
+ warn ("ignoring <delegateURI...> entry for "
+ + uriStartString);
+ } else
+ cat.uriDelegations.put (uriStartString, catalog);
+
+ //
+ // NON-DELEGATING approach to modularity
+ //
+ } else if ("nextCatalog" == local) {
+ if (catalog == null) {
+ error ("expecting <nextCatalog catalog=.../>");
+ return;
+ }
+ if (cat.next == null)
+ cat.next = new Vector ();
+ cat.next.addElement (catalog);
+
+ //
+ // EXTENSIONS from appendix E
+ //
+ } else if ("doctype" == local) {
+ String name = atts.getValue ("name");
+ String value = null;
+
+ if (name == null || uri == null) {
+ error ("expecting <doctype name=... uri=.../>");
+ return;
+ }
+ name = normalizeURI (name);
+ if (cat.doctypes == null)
+ cat.doctypes = new Hashtable ();
+ else
+ value = (String) cat.doctypes.get (name);
+ if (value != null) {
+ if (!value.equals (uri))
+ warn ("ignoring <doctype...> entry for "
+ + uriStartString);
+ } else
+ cat.doctypes.put (name, uri);
+
+
+ //
+ // RESERVED ... ignore (like reserved attributes) but warn
+ //
+ } else {
+ warn ("ignoring unknown catalog element: " + local);
+ ignoreDepth++;
+ }
+ }
+
+ public void endElement (String uri, String local, String qName)
+ throws SAXException
+ {
+ if (ignoreDepth != 0)
+ ignoreDepth--;
+ else
+ bases.pop ();
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/xml/util/XHTMLWriter.java b/libjava/classpath/gnu/xml/util/XHTMLWriter.java
new file mode 100644
index 000000000..3a0c1adb7
--- /dev/null
+++ b/libjava/classpath/gnu/xml/util/XHTMLWriter.java
@@ -0,0 +1,114 @@
+/* XHTMLWriter.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.util;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+
+
+/**
+ * This extends XMLWriter to create a class which defaults to writing
+ * XHTML text, preferring the US-ASCII encoding. It adds no unique
+ * functionality, only changing the defaults slightly to simplify writing
+ * XHTML processing components by providing a bean class whose properties
+ * have more convenient defaults. An artifact of using the US-ASCII
+ * encoding is that no XML declaration is written, so that HTML tools
+ * that can't accept them will not become confused. Components can treat
+ * the output as UTF-8, ISO-8859-1, or US-ASCII without incurring any
+ * data loss.
+ *
+ * @author David Brownell
+ *
+ * @deprecated Please use the javax.xml.stream APIs instead
+ */
+public class XHTMLWriter extends XMLWriter
+{
+ /**
+ * Constructs this handler with System.out used to write
+ * SAX events using the US-ASCII encoding, as XHTML.
+ */
+ public XHTMLWriter ()
+ throws IOException
+ {
+ this (System.out);
+ }
+
+ /**
+ * Constructs this handler such that the specified output stream
+ * is used to write SAX events in the US-ASCII encoding, as XHTML.
+ *
+ * @param out Where US-ASCII encoding of the stream of SAX
+ * events will be sent.
+ */
+ public XHTMLWriter (OutputStream out)
+ throws IOException
+ {
+ // not all JVMs understand "ASCII" as an encoding name, so
+ // we use 8859_1 (they all seem to handle that one) and
+ // make the echo handler filter out non-ASCII characters
+ this (new OutputStreamWriter (out, "8859_1"), "US-ASCII");
+ }
+
+ /**
+ * Constructs this handler such that the specified output stream
+ * is used to write SAX events as XHTML.
+ *
+ * @param out Where the stream of SAX events will be written.
+ */
+ public XHTMLWriter (Writer out)
+ {
+ this (out, null);
+ }
+
+ /**
+ * Constructs this handler such that the specified output stream
+ * is used to write SAX events as XHTML, labeled with the specified
+ * encoding.
+ *
+ * @param out Where the stream of SAX events will be written.
+ * @param encoding If non-null, this names the encoding to be
+ * placed in the encoding declaration.
+ */
+ public XHTMLWriter (Writer out, String encoding)
+ {
+ super (out, encoding);
+ setXhtml (true);
+ }
+}
diff --git a/libjava/classpath/gnu/xml/util/XMLWriter.java b/libjava/classpath/gnu/xml/util/XMLWriter.java
new file mode 100644
index 000000000..a371debff
--- /dev/null
+++ b/libjava/classpath/gnu/xml/util/XMLWriter.java
@@ -0,0 +1,1931 @@
+/* XMLWriter.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.util;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.io.BufferedWriter;
+import java.io.CharConversionException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.util.Stack;
+
+import org.xml.sax.*;
+import org.xml.sax.ext.*;
+import org.xml.sax.helpers.*;
+
+
+/**
+ * This class is a SAX handler which writes all its input as a well formed
+ * XML or XHTML document. If driven using SAX2 events, this output may
+ * include a recreated document type declaration, subject to limitations
+ * of SAX (no internal subset exposed) or DOM (the important declarations,
+ * with their documentation, are discarded).
+ *
+ * <p> By default, text is generated "as-is", but some optional modes
+ * are supported. Pretty-printing is supported, to make life easier
+ * for people reading the output. XHTML (1.0) output has can be made
+ * particularly pretty; all the built-in character entities are known.
+ * Canonical XML can also be generated, assuming the input is properly
+ * formed.
+ *
+ * <hr>
+ *
+ * <p> Some of the methods on this class are intended for applications to
+ * use directly, rather than as pure SAX2 event callbacks. Some of those
+ * methods access the JavaBeans properties (used to tweak output formats,
+ * for example canonicalization and pretty printing). Subclasses
+ * are expected to add new behaviors, not to modify current behavior, so
+ * many such methods are final.</p>
+ *
+ * <p> The <em>write*()</em> methods may be slightly simpler for some
+ * applications to use than direct callbacks. For example, they support
+ * a simple policy for encoding data items as the content of a single element.
+ *
+ * <p> To reuse an XMLWriter you must provide it with a new Writer, since
+ * this handler closes the writer it was given as part of its endDocument()
+ * handling. (XML documents have an end of input, and the way to encode
+ * that on a stream is to close it.) </p>
+ *
+ * <hr>
+ *
+ * <p> Note that any relative URIs in the source document, as found in
+ * entity and notation declarations, ought to have been fully resolved by
+ * the parser providing events to this handler. This means that the
+ * output text should only have fully resolved URIs, which may not be
+ * the desired behavior in cases where later binding is desired. </p>
+ *
+ * <p> <em>Note that due to SAX2 defaults, you may need to manually
+ * ensure that the input events are XML-conformant with respect to namespace
+ * prefixes and declarations. {@link gnu.xml.pipeline.NSFilter} is
+ * one solution to this problem, in the context of processing pipelines.</em>
+ * Something as simple as connecting this handler to a parser might not
+ * generate the correct output. Another workaround is to ensure that the
+ * <em>namespace-prefixes</em> feature is always set to true, if you're
+ * hooking this directly up to some XMLReader implementation.
+ *
+ * @see gnu.xml.pipeline.TextConsumer
+ *
+ * @author David Brownell
+ *
+ * @deprecated Please use the javax.xml.stream APIs instead
+ */
+public class XMLWriter
+ implements ContentHandler, LexicalHandler, DTDHandler, DeclHandler
+{
+ // text prints/escapes differently depending on context
+ // CTX_ENTITY ... entity literal value
+ // CTX_ATTRIBUTE ... attribute literal value
+ // CTX_CONTENT ... content of an element
+ // CTX_UNPARSED ... CDATA, comment, PI, names, etc
+ // CTX_NAME ... name or nmtoken, no escapes possible
+ private static final int CTX_ENTITY = 1;
+ private static final int CTX_ATTRIBUTE = 2;
+ private static final int CTX_CONTENT = 3;
+ private static final int CTX_UNPARSED = 4;
+ private static final int CTX_NAME = 5;
+
+// FIXME: names (element, attribute, PI, notation, etc) are not
+// currently written out with range checks (escapeChars).
+// In non-XHTML, some names can't be directly written; panic!
+
+ private static String sysEOL;
+
+ static {
+ try {
+ sysEOL = System.getProperty ("line.separator", "\n");
+
+ // don't use the system's EOL if it's illegal XML.
+ if (!isLineEnd (sysEOL))
+ sysEOL = "\n";
+
+ } catch (SecurityException e) {
+ sysEOL = "\n";
+ }
+ }
+
+ private static boolean isLineEnd (String eol)
+ {
+ return "\n".equals (eol)
+ || "\r".equals (eol)
+ || "\r\n".equals (eol);
+ }
+
+ private Writer out;
+ private boolean inCDATA;
+ private int elementNestLevel;
+ private String eol = sysEOL;
+
+ private short dangerMask;
+ private CPStringBuilder stringBuf;
+ private Locator locator;
+ private ErrorHandler errHandler;
+
+ private boolean expandingEntities = false;
+ private int entityNestLevel;
+ private boolean xhtml;
+ private boolean startedDoctype;
+ private String encoding;
+
+ private boolean canonical;
+ private boolean inDoctype;
+ private boolean inEpilogue;
+
+ // pretty printing controls
+ private boolean prettyPrinting;
+ private int column;
+ private boolean noWrap;
+ private Stack space = new Stack ();
+
+ // this is not a hard'n'fast rule -- longer lines are OK,
+ // but are to be avoided. Here, prettyprinting is more to
+ // show structure "cleanly" than to be precise about it.
+ // better to have ragged layout than one line 24Kb long.
+ private static final int lineLength = 75;
+
+
+ /**
+ * Constructs this handler with System.out used to write SAX events
+ * using the UTF-8 encoding. Avoid using this except when you know
+ * it's safe to close System.out at the end of the document.
+ */
+ public XMLWriter () throws IOException
+ { this (System.out); }
+
+ /**
+ * Constructs a handler which writes all input to the output stream
+ * in the UTF-8 encoding, and closes it when endDocument is called.
+ * (Yes it's annoying that this throws an exception -- but there's
+ * really no way around it, since it's barely possible a JDK may
+ * exist somewhere that doesn't know how to emit UTF-8.)
+ */
+ public XMLWriter (OutputStream out) throws IOException
+ {
+ this (new OutputStreamWriter (out, "UTF8"));
+ }
+
+ /**
+ * Constructs a handler which writes all input to the writer, and then
+ * closes the writer when the document ends. If an XML declaration is
+ * written onto the output, and this class can determine the name of
+ * the character encoding for this writer, that encoding name will be
+ * included in the XML declaration.
+ *
+ * <P> See the description of the constructor which takes an encoding
+ * name for imporant information about selection of encodings.
+ *
+ * @param writer XML text is written to this writer.
+ */
+ public XMLWriter (Writer writer)
+ {
+ this (writer, null);
+ }
+
+ /**
+ * Constructs a handler which writes all input to the writer, and then
+ * closes the writer when the document ends. If an XML declaration is
+ * written onto the output, this class will use the specified encoding
+ * name in that declaration. If no encoding name is specified, no
+ * encoding name will be declared unless this class can otherwise
+ * determine the name of the character encoding for this writer.
+ *
+ * <P> At this time, only the UTF-8 ("UTF8") and UTF-16 ("Unicode")
+ * output encodings are fully lossless with respect to XML data. If you
+ * use any other encoding you risk having your data be silently mangled
+ * on output, as the standard Java character encoding subsystem silently
+ * maps non-encodable characters to a question mark ("?") and will not
+ * report such errors to applications.
+ *
+ * <p> For a few other encodings the risk can be reduced. If the writer is
+ * a java.io.OutputStreamWriter, and uses either the ISO-8859-1 ("8859_1",
+ * "ISO8859_1", etc) or US-ASCII ("ASCII") encodings, content which
+ * can't be encoded in those encodings will be written safely. Where
+ * relevant, the XHTML entity names will be used; otherwise, numeric
+ * character references will be emitted.
+ *
+ * <P> However, there remain a number of cases where substituting such
+ * entity or character references is not an option. Such references are
+ * not usable within a DTD, comment, PI, or CDATA section. Neither may
+ * they be used when element, attribute, entity, or notation names have
+ * the problematic characters.
+ *
+ * @param writer XML text is written to this writer.
+ * @param encoding if non-null, and an XML declaration is written,
+ * this is the name that will be used for the character encoding.
+ */
+ public XMLWriter (Writer writer, String encoding)
+ {
+ setWriter (writer, encoding);
+ }
+
+ private void setEncoding (String encoding)
+ {
+ if (encoding == null && out instanceof OutputStreamWriter)
+ encoding = ((OutputStreamWriter)out).getEncoding ();
+
+ if (encoding != null) {
+ encoding = encoding.toUpperCase ();
+
+ // Use official encoding names where we know them,
+ // avoiding the Java-only names. When using common
+ // encodings where we can easily tell if characters
+ // are out of range, we'll escape out-of-range
+ // characters using character refs for safety.
+
+ // I _think_ these are all the main synonyms for these!
+ if ("UTF8".equals (encoding)) {
+ encoding = "UTF-8";
+ } else if ("US-ASCII".equals (encoding)
+ || "ASCII".equals (encoding)) {
+ dangerMask = (short) 0xff80;
+ encoding = "US-ASCII";
+ } else if ("ISO-8859-1".equals (encoding)
+ || "8859_1".equals (encoding)
+ || "ISO8859_1".equals (encoding)) {
+ dangerMask = (short) 0xff00;
+ encoding = "ISO-8859-1";
+ } else if ("UNICODE".equals (encoding)
+ || "UNICODE-BIG".equals (encoding)
+ || "UNICODE-LITTLE".equals (encoding)) {
+ encoding = "UTF-16";
+
+ // TODO: UTF-16BE, UTF-16LE ... no BOM; what
+ // release of JDK supports those Unicode names?
+ }
+
+ if (dangerMask != 0)
+ stringBuf = new CPStringBuilder ();
+ }
+
+ this.encoding = encoding;
+ }
+
+
+ /**
+ * Resets the handler to write a new text document.
+ *
+ * @param writer XML text is written to this writer.
+ * @param encoding if non-null, and an XML declaration is written,
+ * this is the name that will be used for the character encoding.
+ *
+ * @exception IllegalStateException if the current
+ * document hasn't yet ended (with {@link #endDocument})
+ */
+ final public void setWriter (Writer writer, String encoding)
+ {
+ if (out != null)
+ throw new IllegalStateException (
+ "can't change stream in mid course");
+ out = writer;
+ if (out != null)
+ setEncoding (encoding);
+ if (!(out instanceof BufferedWriter))
+ out = new BufferedWriter (out);
+ space.push ("default");
+ }
+
+ /**
+ * Assigns the line ending style to be used on output.
+ * @param eolString null to use the system default; else
+ * "\n", "\r", or "\r\n".
+ */
+ final public void setEOL (String eolString)
+ {
+ if (eolString == null)
+ eol = sysEOL;
+ else if (!isLineEnd (eolString))
+ eol = eolString;
+ else
+ throw new IllegalArgumentException (eolString);
+ }
+
+ /**
+ * Assigns the error handler to be used to present most fatal
+ * errors.
+ */
+ public void setErrorHandler (ErrorHandler handler)
+ {
+ errHandler = handler;
+ }
+
+ /**
+ * Used internally and by subclasses, this encapsulates the logic
+ * involved in reporting fatal errors. It uses locator information
+ * for good diagnostics, if available, and gives the application's
+ * ErrorHandler the opportunity to handle the error before throwing
+ * an exception.
+ */
+ protected void fatal (String message, Exception e)
+ throws SAXException
+ {
+ SAXParseException x;
+
+ if (locator == null)
+ x = new SAXParseException (message, null, null, -1, -1, e);
+ else
+ x = new SAXParseException (message, locator, e);
+ if (errHandler != null)
+ errHandler.fatalError (x);
+ throw x;
+ }
+
+
+ // JavaBeans properties
+
+ /**
+ * Controls whether the output should attempt to follow the "transitional"
+ * XHTML rules so that it meets the "HTML Compatibility Guidelines"
+ * appendix in the XHTML specification. A "transitional" Document Type
+ * Declaration (DTD) is placed near the beginning of the output document,
+ * instead of whatever DTD would otherwise have been placed there, and
+ * XHTML empty elements are printed specially. When writing text in
+ * US-ASCII or ISO-8859-1 encodings, the predefined XHTML internal
+ * entity names are used (in preference to character references) when
+ * writing content characters which can't be expressed in those encodings.
+ *
+ * <p> When this option is enabled, it is the caller's responsibility
+ * to ensure that the input is otherwise valid as XHTML. Things to
+ * be careful of in all cases, as described in the appendix referenced
+ * above, include: <ul>
+ *
+ * <li> Element and attribute names must be in lower case, both
+ * in the document and in any CSS style sheet.
+ * <li> All XML constructs must be valid as defined by the XHTML
+ * "transitional" DTD (including all familiar constructs,
+ * even deprecated ones).
+ * <li> The root element must be "html".
+ * <li> Elements that must be empty (such as <em>&lt;br&gt;</em>
+ * must have no content.
+ * <li> Use both <em>lang</em> and <em>xml:lang</em> attributes
+ * when specifying language.
+ * <li> Similarly, use both <em>id</em> and <em>name</em> attributes
+ * when defining elements that may be referred to through
+ * URI fragment identifiers ... and make sure that the
+ * value is a legal NMTOKEN, since not all such HTML 4.0
+ * identifiers are valid in XML.
+ * <li> Be careful with character encodings; make sure you provide
+ * a <em>&lt;meta http-equiv="Content-type"
+ * content="text/xml;charset=..." /&gt;</em> element in
+ * the HTML "head" element, naming the same encoding
+ * used to create this handler. Also, if that encoding
+ * is anything other than US-ASCII, make sure that if
+ * the document is given a MIME content type, it has
+ * a <em>charset=...</em> attribute with that encoding.
+ * </ul>
+ *
+ * <p> Additionally, some of the oldest browsers have additional
+ * quirks, to address with guidelines such as: <ul>
+ *
+ * <li> Processing instructions may be rendered, so avoid them.
+ * (Similarly for an XML declaration.)
+ * <li> Embedded style sheets and scripts should not contain XML
+ * markup delimiters: &amp;, &lt;, and ]]&gt; are trouble.
+ * <li> Attribute values should not have line breaks or multiple
+ * consecutive white space characters.
+ * <li> Use no more than one of the deprecated (transitional)
+ * <em>&lt;isindex&gt;</em> elements.
+ * <li> Some boolean attributes (such as <em>compact, checked,
+ * disabled, readonly, selected,</em> and more) confuse
+ * some browsers, since they only understand minimized
+ * versions which are illegal in XML.
+ * </ul>
+ *
+ * <p> Also, some characteristics of the resulting output may be
+ * a function of whether the document is later given a MIME
+ * content type of <em>text/html</em> rather than one indicating
+ * XML (<em>application/xml</em> or <em>text/xml</em>). Worse,
+ * some browsers ignore MIME content types and prefer to rely URI
+ * name suffixes -- so an "index.xml" could always be XML, never
+ * XHTML, no matter its MIME type.
+ */
+ final public void setXhtml (boolean value)
+ {
+ if (locator != null)
+ throw new IllegalStateException ("started parsing");
+ xhtml = value;
+ if (xhtml)
+ canonical = false;
+ }
+
+ /**
+ * Returns true if the output attempts to echo the input following
+ * "transitional" XHTML rules and matching the "HTML Compatibility
+ * Guidelines" so that an HTML version 3 browser can read the output
+ * as HTML; returns false (the default) othewise.
+ */
+ final public boolean isXhtml ()
+ {
+ return xhtml;
+ }
+
+ /**
+ * Controls whether the output text contains references to
+ * entities (the default), or instead contains the expanded
+ * values of those entities.
+ */
+ final public void setExpandingEntities (boolean value)
+ {
+ if (locator != null)
+ throw new IllegalStateException ("started parsing");
+ expandingEntities = value;
+ if (!expandingEntities)
+ canonical = false;
+ }
+
+ /**
+ * Returns true if the output will have no entity references;
+ * returns false (the default) otherwise.
+ */
+ final public boolean isExpandingEntities ()
+ {
+ return expandingEntities;
+ }
+
+ /**
+ * Controls pretty-printing, which by default is not enabled
+ * (and currently is most useful for XHTML output).
+ * Pretty printing enables structural indentation, sorting of attributes
+ * by name, line wrapping, and potentially other mechanisms for making
+ * output more or less readable.
+ *
+ * <p> At this writing, structural indentation and line wrapping are
+ * enabled when pretty printing is enabled and the <em>xml:space</em>
+ * attribute has the value <em>default</em> (its other legal value is
+ * <em>preserve</em>, as defined in the XML specification). The three
+ * XHTML element types which use another value are recognized by their
+ * names (namespaces are ignored).
+ *
+ * <p> Also, for the record, the "pretty" aspect of printing here
+ * is more to provide basic structure on outputs that would otherwise
+ * risk being a single long line of text. For now, expect the
+ * structure to be ragged ... unless you'd like to submit a patch
+ * to make this be more strictly formatted!
+ *
+ * @exception IllegalStateException thrown if this method is invoked
+ * after output has begun.
+ */
+ final public void setPrettyPrinting (boolean value)
+ {
+ if (locator != null)
+ throw new IllegalStateException ("started parsing");
+ prettyPrinting = value;
+ if (prettyPrinting)
+ canonical = false;
+ }
+
+ /**
+ * Returns value of flag controlling pretty printing.
+ */
+ final public boolean isPrettyPrinting ()
+ {
+ return prettyPrinting;
+ }
+
+
+ /**
+ * Sets the output style to be canonicalized. Input events must
+ * meet requirements that are slightly more stringent than the
+ * basic well-formedness ones, and include: <ul>
+ *
+ * <li> Namespace prefixes must not have been changed from those
+ * in the original document. (This may only be ensured by setting
+ * the SAX2 XMLReader <em>namespace-prefixes</em> feature flag;
+ * by default, it is cleared.)
+ *
+ * <li> Redundant namespace declaration attributes have been
+ * removed. (If an ancestor element defines a namespace prefix
+ * and that declaration hasn't been overriden, an element must
+ * not redeclare it.)
+ *
+ * <li> If comments are not to be included in the canonical output,
+ * they must first be removed from the input event stream; this
+ * <em>Canonical XML with comments</em> by default.
+ *
+ * <li> If the input character encoding was not UCS-based, the
+ * character data must have been normalized using Unicode
+ * Normalization Form C. (UTF-8 and UTF-16 are UCS-based.)
+ *
+ * <li> Attribute values must have been normalized, as is done
+ * by any conformant XML processor which processes all external
+ * parameter entities.
+ *
+ * <li> Similarly, attribute value defaulting has been performed.
+ *
+ * </ul>
+ *
+ * <p> Note that fragments of XML documents, as specified by an XPath
+ * node set, may be canonicalized. In such cases, elements may need
+ * some fixup (for <em>xml:*</em> attributes and application-specific
+ * context).
+ *
+ * @exception IllegalArgumentException if the output encoding
+ * is anything other than UTF-8.
+ */
+ final public void setCanonical (boolean value)
+ {
+ if (value && !"UTF-8".equals (encoding))
+ throw new IllegalArgumentException ("encoding != UTF-8");
+ canonical = value;
+ if (canonical) {
+ prettyPrinting = xhtml = false;
+ expandingEntities = true;
+ eol = "\n";
+ }
+ }
+
+
+ /**
+ * Returns value of flag controlling canonical output.
+ */
+ final public boolean isCanonical ()
+ {
+ return canonical;
+ }
+
+
+ /**
+ * Flushes the output stream. When this handler is used in long lived
+ * pipelines, it can be important to flush buffered state, for example
+ * so that it can reach the disk as part of a state checkpoint.
+ */
+ final public void flush ()
+ throws IOException
+ {
+ if (out != null)
+ out.flush ();
+ }
+
+
+ // convenience routines
+
+// FIXME: probably want a subclass that holds a lot of these...
+// and maybe more!
+
+ /**
+ * Writes the string as if characters() had been called on the contents
+ * of the string. This is particularly useful when applications act as
+ * producers and write data directly to event consumers.
+ */
+ final public void write (String data)
+ throws SAXException
+ {
+ char buf [] = data.toCharArray ();
+ characters (buf, 0, buf.length);
+ }
+
+
+ /**
+ * Writes an element that has content consisting of a single string.
+ * @see #writeEmptyElement
+ * @see #startElement
+ */
+ public void writeElement (
+ String uri,
+ String localName,
+ String qName,
+ Attributes atts,
+ String content
+ ) throws SAXException
+ {
+ if (content == null || content.length () == 0) {
+ writeEmptyElement (uri, localName, qName, atts);
+ return;
+ }
+ startElement (uri, localName, qName, atts);
+ char chars [] = content.toCharArray ();
+ characters (chars, 0, chars.length);
+ endElement (uri, localName, qName);
+ }
+
+
+ /**
+ * Writes an element that has content consisting of a single integer,
+ * encoded as a decimal string.
+ * @see #writeEmptyElement
+ * @see #startElement
+ */
+ public void writeElement (
+ String uri,
+ String localName,
+ String qName,
+ Attributes atts,
+ int content
+ ) throws SAXException
+ {
+ writeElement (uri, localName, qName, atts, Integer.toString (content));
+ }
+
+
+ // SAX1 ContentHandler
+ /** <b>SAX1</b>: provides parser status information */
+ final public void setDocumentLocator (Locator l)
+ {
+ locator = l;
+ }
+
+
+ // URL for dtd that validates against all normal HTML constructs
+ private static final String xhtmlFullDTD =
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd";
+
+
+ /**
+ * <b>SAX1</b>: indicates the beginning of a document parse.
+ * If you're writing (well formed) fragments of XML, neither
+ * this nor endDocument should be called.
+ */
+ // NOT final
+ public void startDocument ()
+ throws SAXException
+ {
+ try {
+ if (out == null)
+ throw new IllegalStateException (
+ "null Writer given to XMLWriter");
+
+ // Not all parsers provide the locator we want; this also
+ // flags whether events are being sent to this object yet.
+ // We could only have this one call if we only printed whole
+ // documents ... but we also print fragments, so most of the
+ // callbacks here replicate this test.
+
+ if (locator == null)
+ locator = new LocatorImpl ();
+
+ // Unless the data is in US-ASCII or we're canonicalizing, write
+ // the XML declaration if we know the encoding. US-ASCII won't
+ // normally get mangled by web server confusion about the
+ // character encodings used. Plus, it's an easy way to
+ // ensure we can write ASCII that's unlikely to confuse
+ // elderly HTML parsers.
+
+ if (!canonical
+ && dangerMask != (short) 0xff80
+ && encoding != null) {
+ rawWrite ("<?xml version='1.0'");
+ rawWrite (" encoding='" + encoding + "'");
+ rawWrite ("?>");
+ newline ();
+ }
+
+ if (xhtml) {
+
+ rawWrite ("<!DOCTYPE html PUBLIC");
+ newline ();
+ rawWrite (" '-//W3C//DTD XHTML 1.0 Transitional//EN'");
+ newline ();
+ rawWrite (" '");
+ // NOTE: URL (above) matches the REC
+ rawWrite (xhtmlFullDTD);
+ rawWrite ("'>");
+ newline ();
+ newline ();
+
+ // fake the rest of the handler into ignoring
+ // everything until the root element, so any
+ // XHTML DTD comments, PIs, etc are ignored
+ startedDoctype = true;
+ }
+
+ entityNestLevel = 0;
+
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /**
+ * <b>SAX1</b>: indicates the completion of a parse.
+ * Note that all complete SAX event streams make this call, even
+ * if an error is reported during a parse.
+ */
+ // NOT final
+ public void endDocument ()
+ throws SAXException
+ {
+ try {
+ if (!canonical) {
+ newline ();
+ newline ();
+ }
+ out.close ();
+ out = null;
+ locator = null;
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ // XHTML elements declared as EMPTY print differently
+ final private static boolean isEmptyElementTag (String tag)
+ {
+ switch (tag.charAt (0)) {
+ case 'a': return "area".equals (tag);
+ case 'b': return "base".equals (tag)
+ || "basefont".equals (tag)
+ || "br".equals (tag);
+ case 'c': return "col".equals (tag);
+ case 'f': return "frame".equals (tag);
+ case 'h': return "hr".equals (tag);
+ case 'i': return "img".equals (tag)
+ || "input".equals (tag)
+ || "isindex".equals (tag);
+ case 'l': return "link".equals (tag);
+ case 'm': return "meta".equals (tag);
+ case 'p': return "param".equals (tag);
+ }
+ return false;
+ }
+
+ private static boolean indentBefore (String tag)
+ {
+ // basically indent before block content
+ // and within structure like tables, lists
+ switch (tag.charAt (0)) {
+ case 'a': return "applet".equals (tag);
+ case 'b': return "body".equals (tag)
+ || "blockquote".equals (tag);
+ case 'c': return "center".equals (tag);
+ case 'f': return "frame".equals (tag)
+ || "frameset".equals (tag);
+ case 'h': return "head".equals (tag);
+ case 'm': return "meta".equals (tag);
+ case 'o': return "object".equals (tag);
+ case 'p': return "param".equals (tag)
+ || "pre".equals (tag);
+ case 's': return "style".equals (tag);
+ case 't': return "title".equals (tag)
+ || "td".equals (tag)
+ || "th".equals (tag);
+ }
+ // ... but not inline elements like "em", "b", "font"
+ return false;
+ }
+
+ private static boolean spaceBefore (String tag)
+ {
+ // blank line AND INDENT before certain structural content
+ switch (tag.charAt (0)) {
+ case 'h': return "h1".equals (tag)
+ || "h2".equals (tag)
+ || "h3".equals (tag)
+ || "h4".equals (tag)
+ || "h5".equals (tag)
+ || "h6".equals (tag)
+ || "hr".equals (tag);
+ case 'l': return "li".equals (tag);
+ case 'o': return "ol".equals (tag);
+ case 'p': return "p".equals (tag);
+ case 't': return "table".equals (tag)
+ || "tr".equals (tag);
+ case 'u': return "ul".equals (tag);
+ }
+ return false;
+ }
+
+ // XHTML DTDs say these three have xml:space="preserve"
+ private static boolean spacePreserve (String tag)
+ {
+ return "pre".equals (tag)
+ || "style".equals (tag)
+ || "script".equals (tag);
+ }
+
+ /**
+ * <b>SAX2</b>: ignored.
+ */
+ final public void startPrefixMapping (String prefix, String uri)
+ {}
+
+ /**
+ * <b>SAX2</b>: ignored.
+ */
+ final public void endPrefixMapping (String prefix)
+ {}
+
+ private void writeStartTag (
+ String name,
+ Attributes atts,
+ boolean isEmpty
+ ) throws SAXException, IOException
+ {
+ rawWrite ('<');
+ rawWrite (name);
+
+ // write out attributes ... sorting is particularly useful
+ // with output that's been heavily defaulted.
+ if (atts != null && atts.getLength () != 0) {
+
+ // Set up to write, with optional sorting
+ int indices [] = new int [atts.getLength ()];
+
+ for (int i= 0; i < indices.length; i++)
+ indices [i] = i;
+
+ // optionally sort
+
+// FIXME: canon xml demands xmlns nodes go first,
+// and sorting by URI first (empty first) then localname
+// it should maybe use a different sort
+
+ if (canonical || prettyPrinting) {
+
+ // insertion sort by attribute name
+ for (int i = 1; i < indices.length; i++) {
+ int n = indices [i], j;
+ String s = atts.getQName (n);
+
+ for (j = i - 1; j >= 0; j--) {
+ if (s.compareTo (atts.getQName (indices [j]))
+ >= 0)
+ break;
+ indices [j + 1] = indices [j];
+ }
+ indices [j + 1] = n;
+ }
+ }
+
+ // write, sorted or no
+ for (int i= 0; i < indices.length; i++) {
+ String s = atts.getQName (indices [i]);
+
+ if (s == null || "".equals (s))
+ throw new IllegalArgumentException ("no XML name");
+ rawWrite (" ");
+ rawWrite (s);
+ rawWrite ("=");
+ writeQuotedValue (atts.getValue (indices [i]),
+ CTX_ATTRIBUTE);
+ }
+ }
+ if (isEmpty)
+ rawWrite (" /");
+ rawWrite ('>');
+ }
+
+ /**
+ * <b>SAX2</b>: indicates the start of an element.
+ * When XHTML is in use, avoid attribute values with
+ * line breaks or multiple whitespace characters, since
+ * not all user agents handle them correctly.
+ */
+ final public void startElement (
+ String uri,
+ String localName,
+ String qName,
+ Attributes atts
+ ) throws SAXException
+ {
+ startedDoctype = false;
+
+ if (locator == null)
+ locator = new LocatorImpl ();
+
+ if (qName == null || "".equals (qName))
+ throw new IllegalArgumentException ("no XML name");
+
+ try {
+ if (entityNestLevel != 0)
+ return;
+ if (prettyPrinting) {
+ String whitespace = null;
+
+ if (xhtml && spacePreserve (qName))
+ whitespace = "preserve";
+ else if (atts != null)
+ whitespace = atts.getValue ("xml:space");
+ if (whitespace == null)
+ whitespace = (String) space.peek ();
+ space.push (whitespace);
+
+ if ("default".equals (whitespace)) {
+ if (xhtml) {
+ if (spaceBefore (qName)) {
+ newline ();
+ doIndent ();
+ } else if (indentBefore (qName))
+ doIndent ();
+ // else it's inlined, modulo line length
+ // FIXME: incrementing element nest level
+ // for inlined elements causes ugliness
+ } else
+ doIndent ();
+ }
+ }
+ elementNestLevel++;
+ writeStartTag (qName, atts, xhtml && isEmptyElementTag (qName));
+
+ if (xhtml) {
+// FIXME: if this is an XHTML "pre" element, turn
+// off automatic wrapping.
+ }
+
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /**
+ * Writes an empty element.
+ * @see #startElement
+ */
+ public void writeEmptyElement (
+ String uri,
+ String localName,
+ String qName,
+ Attributes atts
+ ) throws SAXException
+ {
+ if (canonical) {
+ startElement (uri, localName, qName, atts);
+ endElement (uri, localName, qName);
+ } else {
+ try {
+ writeStartTag (qName, atts, true);
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+ }
+
+
+ /** <b>SAX2</b>: indicates the end of an element */
+ final public void endElement (String uri, String localName, String qName)
+ throws SAXException
+ {
+ if (qName == null || "".equals (qName))
+ throw new IllegalArgumentException ("no XML name");
+
+ try {
+ elementNestLevel--;
+ if (entityNestLevel != 0)
+ return;
+ if (xhtml && isEmptyElementTag (qName))
+ return;
+ rawWrite ("</");
+ rawWrite (qName);
+ rawWrite ('>');
+
+ if (prettyPrinting) {
+ if (!space.empty ())
+ space.pop ();
+ else
+ fatal ("stack discipline", null);
+ }
+ if (elementNestLevel == 0)
+ inEpilogue = true;
+
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** <b>SAX1</b>: reports content characters */
+ final public void characters (char ch [], int start, int length)
+ throws SAXException
+ {
+ if (locator == null)
+ locator = new LocatorImpl ();
+
+ try {
+ if (entityNestLevel != 0)
+ return;
+ if (inCDATA) {
+ escapeChars (ch, start, length, CTX_UNPARSED);
+ } else {
+ escapeChars (ch, start, length, CTX_CONTENT);
+ }
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** <b>SAX1</b>: reports ignorable whitespace */
+ final public void ignorableWhitespace (char ch [], int start, int length)
+ throws SAXException
+ {
+ if (locator == null)
+ locator = new LocatorImpl ();
+
+ try {
+ if (entityNestLevel != 0)
+ return;
+ // don't forget to map NL to CRLF, CR, etc
+ escapeChars (ch, start, length, CTX_CONTENT);
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /**
+ * <b>SAX1</b>: reports a PI.
+ * This doesn't check for illegal target names, such as "xml" or "XML",
+ * or namespace-incompatible ones like "big:dog"; the caller is
+ * responsible for ensuring those names are legal.
+ */
+ final public void processingInstruction (String target, String data)
+ throws SAXException
+ {
+ if (locator == null)
+ locator = new LocatorImpl ();
+
+ // don't print internal subset for XHTML
+ if (xhtml && startedDoctype)
+ return;
+
+ // ancient HTML browsers might render these ... their loss.
+ // to prevent: "if (xhtml) return;".
+
+ try {
+ if (entityNestLevel != 0)
+ return;
+ if (canonical && inEpilogue)
+ newline ();
+ rawWrite ("<?");
+ rawWrite (target);
+ rawWrite (' ');
+ escapeChars (data.toCharArray (), -1, -1, CTX_UNPARSED);
+ rawWrite ("?>");
+ if (elementNestLevel == 0 && !(canonical && inEpilogue))
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** <b>SAX1</b>: indicates a non-expanded entity reference */
+ public void skippedEntity (String name)
+ throws SAXException
+ {
+ try {
+ rawWrite ("&");
+ rawWrite (name);
+ rawWrite (";");
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ // SAX2 LexicalHandler
+
+ /** <b>SAX2</b>: called before parsing CDATA characters */
+ final public void startCDATA ()
+ throws SAXException
+ {
+ if (locator == null)
+ locator = new LocatorImpl ();
+
+ if (canonical)
+ return;
+
+ try {
+ inCDATA = true;
+ if (entityNestLevel == 0)
+ rawWrite ("<![CDATA[");
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** <b>SAX2</b>: called after parsing CDATA characters */
+ final public void endCDATA ()
+ throws SAXException
+ {
+ if (canonical)
+ return;
+
+ try {
+ inCDATA = false;
+ if (entityNestLevel == 0)
+ rawWrite ("]]>");
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /**
+ * <b>SAX2</b>: called when the doctype is partially parsed
+ * Note that this, like other doctype related calls, is ignored
+ * when XHTML is in use.
+ */
+ final public void startDTD (String name, String publicId, String systemId)
+ throws SAXException
+ {
+ if (locator == null)
+ locator = new LocatorImpl ();
+ if (xhtml)
+ return;
+ try {
+ inDoctype = startedDoctype = true;
+ if (canonical)
+ return;
+ rawWrite ("<!DOCTYPE ");
+ rawWrite (name);
+ rawWrite (' ');
+
+ if (!expandingEntities) {
+ if (publicId != null)
+ rawWrite ("PUBLIC '" + publicId + "' '" + systemId + "' ");
+ else if (systemId != null)
+ rawWrite ("SYSTEM '" + systemId + "' ");
+ }
+
+ rawWrite ('[');
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** <b>SAX2</b>: called after the doctype is parsed */
+ final public void endDTD ()
+ throws SAXException
+ {
+ inDoctype = false;
+ if (canonical || xhtml)
+ return;
+ try {
+ rawWrite ("]>");
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /**
+ * <b>SAX2</b>: called before parsing a general entity in content
+ */
+ final public void startEntity (String name)
+ throws SAXException
+ {
+ try {
+ boolean writeEOL = true;
+
+ // Predefined XHTML entities (for characters) will get
+ // mapped back later.
+ if (xhtml || expandingEntities)
+ return;
+
+ entityNestLevel++;
+ if (name.equals ("[dtd]"))
+ return;
+ if (entityNestLevel != 1)
+ return;
+ if (!name.startsWith ("%")) {
+ writeEOL = false;
+ rawWrite ('&');
+ }
+ rawWrite (name);
+ rawWrite (';');
+ if (writeEOL)
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /**
+ * <b>SAX2</b>: called after parsing a general entity in content
+ */
+ final public void endEntity (String name)
+ throws SAXException
+ {
+ if (xhtml || expandingEntities)
+ return;
+ entityNestLevel--;
+ }
+
+ /**
+ * <b>SAX2</b>: called when comments are parsed.
+ * When XHTML is used, the old HTML tradition of using comments
+ * to for inline CSS, or for JavaScript code is discouraged.
+ * This is because XML processors are encouraged to discard, on
+ * the grounds that comments are for users (and perhaps text
+ * editors) not programs. Instead, use external scripts
+ */
+ final public void comment (char ch [], int start, int length)
+ throws SAXException
+ {
+ if (locator == null)
+ locator = new LocatorImpl ();
+
+ // don't print internal subset for XHTML
+ if (xhtml && startedDoctype)
+ return;
+ // don't print comment in doctype for canon xml
+ if (canonical && inDoctype)
+ return;
+
+ try {
+ boolean indent;
+
+ if (prettyPrinting && space.empty ())
+ fatal ("stack discipline", null);
+ indent = prettyPrinting && "default".equals (space.peek ());
+ if (entityNestLevel != 0)
+ return;
+ if (indent)
+ doIndent ();
+ if (canonical && inEpilogue)
+ newline ();
+ rawWrite ("<!--");
+ escapeChars (ch, start, length, CTX_UNPARSED);
+ rawWrite ("-->");
+ if (indent)
+ doIndent ();
+ if (elementNestLevel == 0 && !(canonical && inEpilogue))
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ // SAX1 DTDHandler
+
+ /** <b>SAX1</b>: called on notation declarations */
+ final public void notationDecl (String name,
+ String publicId, String systemId)
+ throws SAXException
+ {
+ if (xhtml)
+ return;
+ try {
+ // At this time, only SAX2 callbacks start these.
+ if (!startedDoctype)
+ return;
+
+ if (entityNestLevel != 0)
+ return;
+ rawWrite ("<!NOTATION " + name + " ");
+ if (publicId != null)
+ rawWrite ("PUBLIC \"" + publicId + '"');
+ else
+ rawWrite ("SYSTEM ");
+ if (systemId != null)
+ rawWrite ('"' + systemId + '"');
+ rawWrite (">");
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** <b>SAX1</b>: called on unparsed entity declarations */
+ final public void unparsedEntityDecl (String name,
+ String publicId, String systemId,
+ String notationName)
+ throws SAXException
+ {
+ if (xhtml)
+ return;
+ try {
+ // At this time, only SAX2 callbacks start these.
+ if (!startedDoctype) {
+ // FIXME: write to temporary buffer, and make the start
+ // of the root element write these declarations.
+ return;
+ }
+
+ if (entityNestLevel != 0)
+ return;
+ rawWrite ("<!ENTITY " + name + " ");
+ if (publicId != null)
+ rawWrite ("PUBLIC \"" + publicId + '"');
+ else
+ rawWrite ("SYSTEM ");
+ rawWrite ('"' + systemId + '"');
+ rawWrite (" NDATA " + notationName + ">");
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ // SAX2 DeclHandler
+
+ /** <b>SAX2</b>: called on attribute declarations */
+ final public void attributeDecl (String eName, String aName,
+ String type, String mode, String value)
+ throws SAXException
+ {
+ if (xhtml)
+ return;
+ try {
+ // At this time, only SAX2 callbacks start these.
+ if (!startedDoctype)
+ return;
+ if (entityNestLevel != 0)
+ return;
+ rawWrite ("<!ATTLIST " + eName + ' ' + aName + ' ');
+ rawWrite (type);
+ rawWrite (' ');
+ if (mode != null)
+ rawWrite (mode + ' ');
+ if (value != null)
+ writeQuotedValue (value, CTX_ATTRIBUTE);
+ rawWrite ('>');
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** <b>SAX2</b>: called on element declarations */
+ final public void elementDecl (String name, String model)
+ throws SAXException
+ {
+ if (xhtml)
+ return;
+ try {
+ // At this time, only SAX2 callbacks start these.
+ if (!startedDoctype)
+ return;
+ if (entityNestLevel != 0)
+ return;
+ rawWrite ("<!ELEMENT " + name + ' ' + model + '>');
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** <b>SAX2</b>: called on external entity declarations */
+ final public void externalEntityDecl (
+ String name,
+ String publicId,
+ String systemId)
+ throws SAXException
+ {
+ if (xhtml)
+ return;
+ try {
+ // At this time, only SAX2 callbacks start these.
+ if (!startedDoctype)
+ return;
+ if (entityNestLevel != 0)
+ return;
+ rawWrite ("<!ENTITY ");
+ if (name.startsWith ("%")) {
+ rawWrite ("% ");
+ rawWrite (name.substring (1));
+ } else
+ rawWrite (name);
+ if (publicId != null)
+ rawWrite (" PUBLIC \"" + publicId + '"');
+ else
+ rawWrite (" SYSTEM ");
+ rawWrite ('"' + systemId + "\">");
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ /** <b>SAX2</b>: called on internal entity declarations */
+ final public void internalEntityDecl (String name, String value)
+ throws SAXException
+ {
+ if (xhtml)
+ return;
+ try {
+ // At this time, only SAX2 callbacks start these.
+ if (!startedDoctype)
+ return;
+ if (entityNestLevel != 0)
+ return;
+ rawWrite ("<!ENTITY ");
+ if (name.startsWith ("%")) {
+ rawWrite ("% ");
+ rawWrite (name.substring (1));
+ } else
+ rawWrite (name);
+ rawWrite (' ');
+ writeQuotedValue (value, CTX_ENTITY);
+ rawWrite ('>');
+ newline ();
+ } catch (IOException e) {
+ fatal ("can't write", e);
+ }
+ }
+
+ private void writeQuotedValue (String value, int code)
+ throws SAXException, IOException
+ {
+ char buf [] = value.toCharArray ();
+ int off = 0, len = buf.length;
+
+ // we can't add line breaks to attribute/entity/... values
+ noWrap = true;
+ rawWrite ('"');
+ escapeChars (buf, off, len, code);
+ rawWrite ('"');
+ noWrap = false;
+ }
+
+ // From "HTMLlat1x.ent" ... names of entities for ISO-8859-1
+ // (Latin/1) characters, all codes: 160-255 (0xA0-0xFF).
+ // Codes 128-159 have no assigned values.
+ private static final String HTMLlat1x [] = {
+ // 160
+ "nbsp", "iexcl", "cent", "pound", "curren",
+ "yen", "brvbar", "sect", "uml", "copy",
+
+ // 170
+ "ordf", "laquo", "not", "shy", "reg",
+ "macr", "deg", "plusmn", "sup2", "sup3",
+
+ // 180
+ "acute", "micro", "para", "middot", "cedil",
+ "sup1", "ordm", "raquo", "frac14", "frac12",
+
+ // 190
+ "frac34", "iquest", "Agrave", "Aacute", "Acirc",
+ "Atilde", "Auml", "Aring", "AElig", "Ccedil",
+
+ // 200
+ "Egrave", "Eacute", "Ecirc", "Euml", "Igrave",
+ "Iacute", "Icirc", "Iuml", "ETH", "Ntilde",
+
+ // 210
+ "Ograve", "Oacute", "Ocirc", "Otilde", "Ouml",
+ "times", "Oslash", "Ugrave", "Uacute", "Ucirc",
+
+ // 220
+ "Uuml", "Yacute", "THORN", "szlig", "agrave",
+ "aacute", "acirc", "atilde", "auml", "aring",
+
+ // 230
+ "aelig", "ccedil", "egrave", "eacute", "ecirc",
+ "euml", "igrave", "iacute", "icirc", "iuml",
+
+ // 240
+ "eth", "ntilde", "ograve", "oacute", "ocirc",
+ "otilde", "ouml", "divide", "oslash", "ugrave",
+
+ // 250
+ "uacute", "ucirc", "uuml", "yacute", "thorn",
+ "yuml"
+ };
+
+ // From "HTMLsymbolx.ent" ... some of the symbols that
+ // we can conveniently handle. Entities for the Greek.
+ // alphabet (upper and lower cases) are compact.
+ private static final String HTMLsymbolx_GR [] = {
+ // 913
+ "Alpha", "Beta", "Gamma", "Delta", "Epsilon",
+ "Zeta", "Eta", "Theta", "Iota", "Kappa",
+
+ // 923
+ "Lambda", "Mu", "Nu", "Xi", "Omicron",
+ "Pi", "Rho", null, "Sigma", "Tau",
+
+ // 933
+ "Upsilon", "Phi", "Chi", "Psi", "Omega"
+ };
+
+ private static final String HTMLsymbolx_gr [] = {
+ // 945
+ "alpha", "beta", "gamma", "delta", "epsilon",
+ "zeta", "eta", "theta", "iota", "kappa",
+
+ // 955
+ "lambda", "mu", "nu", "xi", "omicron",
+ "pi", "rho", "sigmaf", "sigma", "tau",
+
+ // 965
+ "upsilon", "phi", "chi", "psi", "omega"
+ };
+
+
+ // General routine to write text and substitute predefined
+ // entities (XML, and a special case for XHTML) as needed.
+ private void escapeChars (char buf [], int off, int len, int code)
+ throws SAXException, IOException
+ {
+ int first = 0;
+
+ if (off < 0) {
+ off = 0;
+ len = buf.length;
+ }
+ for (int i = 0; i < len; i++) {
+ String esc;
+ char c = buf [off + i];
+
+ switch (c) {
+ // Note that CTX_ATTRIBUTE isn't explicitly tested here;
+ // all syntax delimiters are escaped in CTX_ATTRIBUTE,
+ // otherwise it's similar to CTX_CONTENT
+
+ // ampersand flags entity references; entity replacement
+ // text has unexpanded references, other text doesn't.
+ case '&':
+ if (code == CTX_ENTITY || code == CTX_UNPARSED)
+ continue;
+ esc = "amp";
+ break;
+
+ // attributes and text may NOT have literal '<', but
+ // entities may have markup constructs
+ case '<':
+ if (code == CTX_ENTITY || code == CTX_UNPARSED)
+ continue;
+ esc = "lt";
+ break;
+
+ // as above re markup constructs; but otherwise
+ // except when canonicalizing, this is for consistency
+ case '>':
+ if (code == CTX_ENTITY || code == CTX_UNPARSED)
+ continue;
+ esc = "gt";
+ break;
+ case '\'':
+ if (code == CTX_CONTENT || code == CTX_UNPARSED)
+ continue;
+ if (canonical)
+ continue;
+ esc = "apos";
+ break;
+
+ // needed when printing quoted attribute/entity values
+ case '"':
+ if (code == CTX_CONTENT || code == CTX_UNPARSED)
+ continue;
+ esc = "quot";
+ break;
+
+ // make line ends work per host OS convention
+ case '\n':
+ esc = eol;
+ break;
+
+ //
+ // No other characters NEED special treatment ... except
+ // for encoding-specific issues, like whether the character
+ // can really be represented in that encoding.
+ //
+ default:
+ //
+ // There are characters we can never write safely; getting
+ // them is an error.
+ //
+ // (a) They're never legal in XML ... detected by range
+ // checks, and (eventually) by remerging surrogate
+ // pairs on output. (Easy error for apps to prevent.)
+ //
+ // (b) This encoding can't represent them, and we
+ // can't make reference substitution (e.g. inside
+ // CDATA sections, names, PI data, etc). (Hard for
+ // apps to prevent, except by using UTF-8 or UTF-16
+ // as their output encoding.)
+ //
+ // We know a very little bit about what characters
+ // the US-ASCII and ISO-8859-1 encodings support. For
+ // other encodings we can't detect the second type of
+ // error at all. (Never an issue for UTF-8 or UTF-16.)
+ //
+
+// FIXME: CR in CDATA is an error; in text, turn to a char ref
+
+// FIXME: CR/LF/TAB in attributes should become char refs
+
+ if ((c > 0xfffd)
+ || ((c < 0x0020) && !((c == 0x0009)
+ || (c == 0x000A) || (c == 0x000D)))
+ || (((c & dangerMask) != 0)
+ && (code == CTX_UNPARSED))) {
+
+ // if case (b) in CDATA, we might end the section,
+ // write a reference, then restart ... possible
+ // in one DOM L3 draft.
+
+ throw new CharConversionException (
+ "Illegal or non-writable character: U+"
+ + Integer.toHexString (c));
+ }
+
+ //
+ // If the output encoding represents the character
+ // directly, let it do so! Else we'll escape it.
+ //
+ if ((c & dangerMask) == 0)
+ continue;
+ esc = null;
+
+ // Avoid numeric refs where symbolic ones exist, as
+ // symbolic ones make more sense to humans reading!
+ if (xhtml) {
+ // all the HTMLlat1x.ent entities
+ // (all the "ISO-8859-1" characters)
+ if (c >= 160 && c <= 255)
+ esc = HTMLlat1x [c - 160];
+
+ // not quite half the HTMLsymbolx.ent entities
+ else if (c >= 913 && c <= 937)
+ esc = HTMLsymbolx_GR [c - 913];
+ else if (c >= 945 && c <= 969)
+ esc = HTMLsymbolx_gr [c - 945];
+
+ else switch (c) {
+ // all of the HTMLspecialx.ent entities
+ case 338: esc = "OElig"; break;
+ case 339: esc = "oelig"; break;
+ case 352: esc = "Scaron"; break;
+ case 353: esc = "scaron"; break;
+ case 376: esc = "Yuml"; break;
+ case 710: esc = "circ"; break;
+ case 732: esc = "tilde"; break;
+ case 8194: esc = "ensp"; break;
+ case 8195: esc = "emsp"; break;
+ case 8201: esc = "thinsp"; break;
+ case 8204: esc = "zwnj"; break;
+ case 8205: esc = "zwj"; break;
+ case 8206: esc = "lrm"; break;
+ case 8207: esc = "rlm"; break;
+ case 8211: esc = "ndash"; break;
+ case 8212: esc = "mdash"; break;
+ case 8216: esc = "lsquo"; break;
+ case 8217: esc = "rsquo"; break;
+ case 8218: esc = "sbquo"; break;
+ case 8220: esc = "ldquo"; break;
+ case 8221: esc = "rdquo"; break;
+ case 8222: esc = "bdquo"; break;
+ case 8224: esc = "dagger"; break;
+ case 8225: esc = "Dagger"; break;
+ case 8240: esc = "permil"; break;
+ case 8249: esc = "lsaquo"; break;
+ case 8250: esc = "rsaquo"; break;
+ case 8364: esc = "euro"; break;
+
+ // the other HTMLsymbox.ent entities
+ case 402: esc = "fnof"; break;
+ case 977: esc = "thetasym"; break;
+ case 978: esc = "upsih"; break;
+ case 982: esc = "piv"; break;
+ case 8226: esc = "bull"; break;
+ case 8230: esc = "hellip"; break;
+ case 8242: esc = "prime"; break;
+ case 8243: esc = "Prime"; break;
+ case 8254: esc = "oline"; break;
+ case 8260: esc = "frasl"; break;
+ case 8472: esc = "weierp"; break;
+ case 8465: esc = "image"; break;
+ case 8476: esc = "real"; break;
+ case 8482: esc = "trade"; break;
+ case 8501: esc = "alefsym"; break;
+ case 8592: esc = "larr"; break;
+ case 8593: esc = "uarr"; break;
+ case 8594: esc = "rarr"; break;
+ case 8595: esc = "darr"; break;
+ case 8596: esc = "harr"; break;
+ case 8629: esc = "crarr"; break;
+ case 8656: esc = "lArr"; break;
+ case 8657: esc = "uArr"; break;
+ case 8658: esc = "rArr"; break;
+ case 8659: esc = "dArr"; break;
+ case 8660: esc = "hArr"; break;
+ case 8704: esc = "forall"; break;
+ case 8706: esc = "part"; break;
+ case 8707: esc = "exist"; break;
+ case 8709: esc = "empty"; break;
+ case 8711: esc = "nabla"; break;
+ case 8712: esc = "isin"; break;
+ case 8713: esc = "notin"; break;
+ case 8715: esc = "ni"; break;
+ case 8719: esc = "prod"; break;
+ case 8721: esc = "sum"; break;
+ case 8722: esc = "minus"; break;
+ case 8727: esc = "lowast"; break;
+ case 8730: esc = "radic"; break;
+ case 8733: esc = "prop"; break;
+ case 8734: esc = "infin"; break;
+ case 8736: esc = "ang"; break;
+ case 8743: esc = "and"; break;
+ case 8744: esc = "or"; break;
+ case 8745: esc = "cap"; break;
+ case 8746: esc = "cup"; break;
+ case 8747: esc = "int"; break;
+ case 8756: esc = "there4"; break;
+ case 8764: esc = "sim"; break;
+ case 8773: esc = "cong"; break;
+ case 8776: esc = "asymp"; break;
+ case 8800: esc = "ne"; break;
+ case 8801: esc = "equiv"; break;
+ case 8804: esc = "le"; break;
+ case 8805: esc = "ge"; break;
+ case 8834: esc = "sub"; break;
+ case 8835: esc = "sup"; break;
+ case 8836: esc = "nsub"; break;
+ case 8838: esc = "sube"; break;
+ case 8839: esc = "supe"; break;
+ case 8853: esc = "oplus"; break;
+ case 8855: esc = "otimes"; break;
+ case 8869: esc = "perp"; break;
+ case 8901: esc = "sdot"; break;
+ case 8968: esc = "lceil"; break;
+ case 8969: esc = "rceil"; break;
+ case 8970: esc = "lfloor"; break;
+ case 8971: esc = "rfloor"; break;
+ case 9001: esc = "lang"; break;
+ case 9002: esc = "rang"; break;
+ case 9674: esc = "loz"; break;
+ case 9824: esc = "spades"; break;
+ case 9827: esc = "clubs"; break;
+ case 9829: esc = "hearts"; break;
+ case 9830: esc = "diams"; break;
+ }
+ }
+
+ // else escape with numeric char refs
+ if (esc == null) {
+ stringBuf.setLength (0);
+ stringBuf.append ("#x");
+ stringBuf.append (Integer.toHexString (c).toUpperCase ());
+ esc = stringBuf.toString ();
+
+ // FIXME: We don't write surrogate pairs correctly.
+ // They should work as one ref per character, since
+ // each pair is one character. For reading back into
+ // Unicode, it matters beginning in Unicode 3.1 ...
+ }
+ break;
+ }
+ if (i != first)
+ rawWrite (buf, off + first, i - first);
+ first = i + 1;
+ if (esc == eol)
+ newline ();
+ else {
+ rawWrite ('&');
+ rawWrite (esc);
+ rawWrite (';');
+ }
+ }
+ if (first < len)
+ rawWrite (buf, off + first, len - first);
+ }
+
+
+
+ private void newline ()
+ throws SAXException, IOException
+ {
+ out.write (eol);
+ column = 0;
+ }
+
+ private void doIndent ()
+ throws SAXException, IOException
+ {
+ int space = elementNestLevel * 2;
+
+ newline ();
+ column = space;
+ // track tabs only at line starts
+ while (space > 8) {
+ out.write ("\t");
+ space -= 8;
+ }
+ while (space > 0) {
+ out.write (" ");
+ space -= 2;
+ }
+ }
+
+ private void rawWrite (char c)
+ throws IOException
+ {
+ out.write (c);
+ column++;
+ }
+
+ private void rawWrite (String s)
+ throws SAXException, IOException
+ {
+ if (prettyPrinting && "default".equals (space.peek ())) {
+ char data [] = s.toCharArray ();
+ rawWrite (data, 0, data.length);
+ } else {
+ out.write (s);
+ column += s.length ();
+ }
+ }
+
+ // NOTE: if xhtml, the REC gives some rules about whitespace
+ // which we could follow ... notably, many places where conformant
+ // agents "must" consolidate/normalize whitespace. Line ends can
+ // be removed there, etc. This may not be the right place to do
+ // such mappings though.
+
+ // Line buffering may help clarify algorithms and improve results.
+
+ // It's likely xml:space needs more attention.
+
+ private void rawWrite (char buf [], int offset, int length)
+ throws SAXException, IOException
+ {
+ boolean wrap;
+
+ if (prettyPrinting && space.empty ())
+ fatal ("stack discipline", null);
+
+ wrap = prettyPrinting && "default".equals (space.peek ());
+ if (!wrap) {
+ out.write (buf, offset, length);
+ column += length;
+ return;
+ }
+
+ // we're pretty printing and want to fill lines out only
+ // to the desired line length.
+ while (length > 0) {
+ int target = lineLength - column;
+ boolean wrote = false;
+
+ // Do we even have a problem?
+ if (target > length || noWrap) {
+ out.write (buf, offset, length);
+ column += length;
+ return;
+ }
+
+ // break the line at a space character, trying to fill
+ // as much of the line as possible.
+ char c;
+
+ for (int i = target - 1; i >= 0; i--) {
+ if ((c = buf [offset + i]) == ' ' || c == '\t') {
+ i++;
+ out.write (buf, offset, i);
+ doIndent ();
+ offset += i;
+ length -= i;
+ wrote = true;
+ break;
+ }
+ }
+ if (wrote)
+ continue;
+
+ // no space character permitting break before target
+ // line length is filled. So, take the next one.
+ if (target < 0)
+ target = 0;
+ for (int i = target; i < length; i++)
+ if ((c = buf [offset + i]) == ' ' || c == '\t') {
+ i++;
+ out.write (buf, offset, i);
+ doIndent ();
+ offset += i;
+ length -= i;
+ wrote = true;
+ break;
+ }
+ if (wrote)
+ continue;
+
+ // no such luck.
+ out.write (buf, offset, length);
+ column += length;
+ break;
+ }
+ }
+}
diff --git a/libjava/classpath/gnu/xml/util/package.html b/libjava/classpath/gnu/xml/util/package.html
new file mode 100644
index 000000000..6e6c0d77d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/util/package.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html PUBLIC
+ "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/1999/PR-xhtml1-19991210/DTD/xhtml1-transitional.dtd">
+
+<html><head><title> org.brownell.xml package </title> </head>
+<!--
+/*
+ * Copyright (C) 1999,2000 The Free Software Foundation, Inc.
+ */
+-->
+<body>
+ <p> This package contains XML utilities, including SAX2 XML writers
+ and a parser of DOM trees, plus a command line driver.
+ That <a href="DoParse.html">driver</a>
+ connects parsers simple processing pipelines.
+ It can be handy for command line validation or
+ transformation tasks, possibly in batch mode,
+ or within Makefiles. </p>
+
+</body></html>
diff --git a/libjava/classpath/gnu/xml/validation/datatype/Annotation.java b/libjava/classpath/gnu/xml/validation/datatype/Annotation.java
new file mode 100644
index 000000000..6438e2ebb
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/Annotation.java
@@ -0,0 +1,60 @@
+/* Annotation.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+/**
+ * A schema component annotation.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class Annotation
+{
+
+ public final String documentation;
+
+ public Annotation(String documentation)
+ {
+ this.documentation = documentation;
+ }
+
+ public String toString()
+ {
+ return documentation;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/AnySimpleType.java b/libjava/classpath/gnu/xml/validation/datatype/AnySimpleType.java
new file mode 100644
index 000000000..36fb98daa
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/AnySimpleType.java
@@ -0,0 +1,58 @@
+/* AnySimpleType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.Set;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+
+final class AnySimpleType
+ extends SimpleType
+{
+
+ AnySimpleType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "anySimpleType"),
+ ANY, /* variety */
+ (Set) null, /* facets */
+ 0, /* fundametalFacets */
+ (SimpleType) Type.ANY_TYPE, /* baseType */
+ null);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/AnyType.java b/libjava/classpath/gnu/xml/validation/datatype/AnyType.java
new file mode 100644
index 000000000..2a3f116dd
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/AnyType.java
@@ -0,0 +1,57 @@
+/* AnyType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+
+final class AnyType
+ extends SimpleType
+{
+
+ AnyType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "anyType"),
+ ANY, /* variety */
+ null, /* facets */
+ 0, /* fundamentalFacets */
+ null, /* baseType */
+ null);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/AnyURIType.java b/libjava/classpath/gnu/xml/validation/datatype/AnyURIType.java
new file mode 100644
index 000000000..ef409b99c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/AnyURIType.java
@@ -0,0 +1,93 @@
+/* AnyURIType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.net.URI;
+import java.net.URISyntaxException;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema anyURI type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class AnyURIType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ AnyURIType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "anyURI"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ try
+ {
+ new URI(value);
+ }
+ catch (URISyntaxException e)
+ {
+ DatatypeException e2 = new DatatypeException(e.getIndex(),
+ e.getReason());
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/AtomicSimpleType.java b/libjava/classpath/gnu/xml/validation/datatype/AtomicSimpleType.java
new file mode 100644
index 000000000..38528eecf
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/AtomicSimpleType.java
@@ -0,0 +1,77 @@
+/* AtomicSimpleType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.Set;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * An XML Schema atomic simple type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class AtomicSimpleType
+ extends SimpleType
+{
+
+ public AtomicSimpleType(QName name,
+ Set facets,
+ int fundamentalFacets,
+ SimpleType baseType,
+ Annotation annotation)
+ {
+ super(name, ATOMIC, facets, fundamentalFacets, baseType, annotation);
+ }
+
+ // Only for use by built-in types
+ AtomicSimpleType(QName name, SimpleType baseType)
+ {
+ super(name, ATOMIC, null, 0, baseType, null);
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ if (baseType != null)
+ baseType.checkValid(value, context);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/Base64BinaryType.java b/libjava/classpath/gnu/xml/validation/datatype/Base64BinaryType.java
new file mode 100644
index 000000000..3f3442f8c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/Base64BinaryType.java
@@ -0,0 +1,128 @@
+/* Base64BinaryType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema base64Binary type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class Base64BinaryType
+ extends AtomicSimpleType
+{
+
+ static final String B64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
+ "abcdefghijklmnopqrstuvwxyz0123456789+/";
+ static final String B16 = "AEIMQUYcgkosw048";
+ static final String B04 = "AQgw";
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ Base64BinaryType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "base64Binary"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ // TODO value = collapseWhitespace(value);
+ int len = value.length();
+ try
+ {
+ for (int i = len - 1; i >= 0; )
+ {
+ char c4 = value.charAt(i--);
+ if (c4 == ' ')
+ c4 = value.charAt(i--);
+ char c3 = value.charAt(i--);
+ if (c3 == ' ')
+ c3 = value.charAt(i--);
+ char c2 = value.charAt(i--);
+ if (c2 == ' ')
+ c2 = value.charAt(i--);
+ char c1 = value.charAt(i--);
+ if (c1 == ' ')
+ c1 = value.charAt(i--);
+
+ if (c4 == '=')
+ {
+ if (c3 == '=')
+ {
+ if (B04.indexOf(c2) != -1 &&
+ B64.indexOf(c1) != -1)
+ continue;
+ }
+ else if (B16.indexOf(c3) != -1)
+ {
+ if (B64.indexOf(c2) != -1 &&
+ B64.indexOf(c1) != -1)
+ continue;
+ }
+ }
+ else if (B64.indexOf(c4) != -1)
+ continue;
+ throw new DatatypeException(i, "illegal BASE64");
+ }
+ }
+ catch (IndexOutOfBoundsException e)
+ {
+ throw new DatatypeException("illegal BASE64");
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/BooleanType.java b/libjava/classpath/gnu/xml/validation/datatype/BooleanType.java
new file mode 100644
index 000000000..5d98d2412
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/BooleanType.java
@@ -0,0 +1,89 @@
+/* BooleanType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema boolean type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class BooleanType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.PATTERN,
+ Facet.WHITESPACE
+ };
+
+ static final Set VALUE_SPACE =
+ new TreeSet(Arrays.asList(new String[] {"true", "false", "1", "0"}));
+
+ BooleanType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "boolean"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ if (!VALUE_SPACE.contains(value))
+ throw new DatatypeException("invalid boolean value");
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ return ("1".equals(literal) || "true".equals(literal)) ? Boolean.TRUE :
+ Boolean.FALSE;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/ByteType.java b/libjava/classpath/gnu/xml/validation/datatype/ByteType.java
new file mode 100644
index 000000000..9bce45bf9
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/ByteType.java
@@ -0,0 +1,132 @@
+/* ByteType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema byte type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class ByteType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.TOTAL_DIGITS,
+ Facet.FRACTION_DIGITS,
+ Facet.PATTERN,
+ Facet.WHITESPACE,
+ Facet.ENUMERATION,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ static final String MAX_VALUE = "127";
+ static final String MIN_VALUE = "128";
+ static final int LENGTH = MAX_VALUE.length();
+
+ ByteType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "byte"),
+ TypeLibrary.SHORT);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValue(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException(0, "invalid byte value");
+ int i = 0, off = 0;
+ boolean compare = false;
+ String compareTo = MAX_VALUE;
+ char c = value.charAt(0);
+ if (c == '+')
+ i++;
+ else if (c == '-')
+ {
+ compareTo = MIN_VALUE;
+ i++;
+ }
+ if (len - i > LENGTH)
+ throw new DatatypeException(0, "invalid byte value");
+ else if (len - i == LENGTH)
+ compare = true;
+ for (; i < len; i++)
+ {
+ c = value.charAt(i);
+ if (c >= 0x30 && c <= 0x39)
+ {
+ if (compare)
+ {
+ char d = compareTo.charAt(off);
+ if (Character.digit(c, 10) > Character.digit(d, 10))
+ throw new DatatypeException(i, "invalid byte value");
+ }
+ off++;
+ continue;
+ }
+ throw new DatatypeException(i, "invalid byte value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new Byte(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/DateTimeType.java b/libjava/classpath/gnu/xml/validation/datatype/DateTimeType.java
new file mode 100644
index 000000000..81d2785bc
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/DateTimeType.java
@@ -0,0 +1,334 @@
+/* DateTimeType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema dateTime type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class DateTimeType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ DateTimeType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "dateTime"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValue(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ int state = 0;
+ int start = 0;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == '-' && i == 0)
+ {
+ start++;
+ continue;
+ }
+ if (c >= 0x30 && c <= 0x39)
+ continue;
+ switch (state)
+ {
+ case 0: // year
+ if (c == '-')
+ {
+ String year = value.substring(start, i);
+ if ("0000".equals(year) || year.length() < 4)
+ throw new DatatypeException(i, "invalid dateTime value");
+ state = 1;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 1: // month
+ if (c == '-')
+ {
+ if (i - start != 2)
+ throw new DatatypeException(i, "invalid dateTime value");
+ state = 2;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 2: // day
+ if (c == 'T')
+ {
+ if (i - start != 2)
+ throw new DatatypeException(i, "invalid dateTime value");
+ state = 3;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 3: // hour
+ if (c == ':')
+ {
+ if (i - start != 2)
+ throw new DatatypeException(i, "invalid dateTime value");
+ state = 4;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 4: // minute
+ if (c == ':')
+ {
+ if (i - start != 2)
+ throw new DatatypeException(i, "invalid dateTime value");
+ state = 5;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 5: // second
+ if (c == '.')
+ {
+ if (i - start != 2)
+ throw new DatatypeException(i, "invalid dateTime value");
+ state = 6;
+ start = i + 1;
+ continue;
+ }
+ else if (c == ' ')
+ {
+ if (i - start != 2)
+ throw new DatatypeException(i, "invalid dateTime value");
+ state = 7;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 6: // second fraction
+ if (c == ' ')
+ {
+ state = 7;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 7: // timezone 1
+ if (start == i)
+ {
+ if (c == '+' || c == '-')
+ continue;
+ else if (c == 'Z')
+ {
+ state = 9;
+ start = i + 1;
+ continue;
+ }
+ }
+ if (c == ':')
+ {
+ if (i - start != 2)
+ throw new DatatypeException(i, "invalid dateTime value");
+ state = 8;
+ start = i + 1;
+ continue;
+ }
+ break;
+ }
+ throw new DatatypeException(i, "invalid dateTime value");
+ }
+ switch (state)
+ {
+ case 5: // second
+ if (len - start != 2)
+ throw new DatatypeException(len, "invalid dateTime value");
+ break;
+ case 6: // second fraction
+ break;
+ case 8: // timezone 2
+ if (len - start != 2)
+ throw new DatatypeException(len, "invalid dateTime value");
+ break;
+ case 9: // post Z
+ break;
+ default:
+ throw new DatatypeException(len, "invalid dateTime value");
+ }
+ }
+
+ public Object createValue(String value, ValidationContext context) {
+ int len = value.length();
+ int state = 0;
+ int start = 0;
+ Calendar cal = new GregorianCalendar();
+ try
+ {
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == '-' && i == 0)
+ {
+ start++;
+ continue;
+ }
+ if (c >= 0x30 && c <= 0x39)
+ continue;
+ switch (state)
+ {
+ case 0: // year
+ if (c == '-')
+ {
+ cal.set(Calendar.YEAR,
+ Integer.parseInt(value.substring(0, i)));
+ state = 1;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 1: // month
+ if (c == '-')
+ {
+ cal.set(Calendar.MONTH,
+ Integer.parseInt(value.substring(start, i)));
+ state = 2;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 2: // day
+ if (c == 'T')
+ {
+ cal.set(Calendar.DATE,
+ Integer.parseInt(value.substring(start, i)));
+ state = 3;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 3: // hour
+ if (c == ':')
+ {
+ cal.set(Calendar.HOUR,
+ Integer.parseInt(value.substring(start, i)));
+ state = 4;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 4: // minute
+ if (c == ':')
+ {
+ cal.set(Calendar.MINUTE,
+ Integer.parseInt(value.substring(start, i)));
+ state = 5;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 5: // second
+ if (c == ' ')
+ {
+ float second = Float.parseFloat(value.substring(start, i));
+ // TODO adjust non-integer values
+ cal.set(Calendar.SECOND, (int) second);
+ state = 7;
+ start = i + 1;
+ continue;
+ }
+ break;
+ }
+ }
+ // end of input
+ if (len - start > 0 && state == 7)
+ {
+ // Timezone
+ String timezone = value.substring(len - start);
+ int i = timezone.indexOf(':');
+ if (i == -1)
+ {
+ if ("Z".equals(timezone))
+ timezone = "UTC";
+ TimeZone tz = TimeZone.getTimeZone(timezone);
+ if (tz == null)
+ return null;
+ cal.set(Calendar.ZONE_OFFSET, tz.getRawOffset());
+ }
+ else
+ {
+ String tzh = timezone.substring(0, i);
+ String tzm = timezone.substring(i + 1);
+ int offset = Integer.parseInt(tzh) * 360000;
+ if (offset < 0)
+ offset -= Integer.parseInt(tzm) * 60000;
+ else
+ offset += Integer.parseInt(tzm) * 60000;
+ cal.set(Calendar.ZONE_OFFSET, offset);
+ }
+ }
+ return cal.getTime();
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/DateType.java b/libjava/classpath/gnu/xml/validation/datatype/DateType.java
new file mode 100644
index 000000000..8e6e3c35a
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/DateType.java
@@ -0,0 +1,221 @@
+/* DateType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.Calendar;
+import java.util.GregorianCalendar;
+import java.util.TimeZone;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema date type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class DateType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ DateType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "date"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ int state = 0;
+ int start = 0;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == '-' && i == 0)
+ {
+ start++;
+ continue;
+ }
+ if (c >= 0x30 && c <= 0x39)
+ continue;
+ switch (state)
+ {
+ case 0: // year
+ if (c == '-')
+ {
+ String year = value.substring(start, i);
+ if ("0000".equals(year) || year.length() < 4)
+ throw new DatatypeException(i, "invalid date value");
+ state = 1;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 1: // month
+ if (c == '-')
+ {
+ if (i - start != 2)
+ throw new DatatypeException(i, "invalid date value");
+ state = 2;
+ start = i + 1;
+ continue;
+ }
+ break;
+ }
+ throw new DatatypeException(i, "invalid date value");
+ }
+ switch (state)
+ {
+ case 2: // day
+ if (len - start != 2)
+ throw new DatatypeException("invalid date value");
+ break;
+ default:
+ throw new DatatypeException("invalid date value");
+ }
+ }
+
+ public Object createValue(String value, ValidationContext context) {
+ int len = value.length();
+ int state = 0;
+ int start = 0;
+ Calendar cal = new GregorianCalendar();
+ cal.set(Calendar.HOUR, 0);
+ cal.set(Calendar.MINUTE, 0);
+ cal.set(Calendar.SECOND, 0);
+ try
+ {
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == '-' && i == 0)
+ {
+ start++;
+ continue;
+ }
+ if (c >= 0x30 && c <= 0x39)
+ continue;
+ switch (state)
+ {
+ case 0: // year
+ if (c == '-')
+ {
+ cal.set(Calendar.YEAR,
+ Integer.parseInt(value.substring(0, i)));
+ state = 1;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 1: // month
+ if (c == '-')
+ {
+ cal.set(Calendar.MONTH,
+ Integer.parseInt(value.substring(start, i)));
+ state = 2;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 2: // day
+ if (c == 'T')
+ {
+ cal.set(Calendar.DATE,
+ Integer.parseInt(value.substring(start, i)));
+ state = 7;
+ start = i + 1;
+ continue;
+ }
+ break;
+ }
+ }
+ // end of input
+ if (len - start > 0 && state == 7)
+ {
+ // Timezone
+ String timezone = value.substring(len - start);
+ int i = timezone.indexOf(':');
+ if (i == -1)
+ {
+ if ("Z".equals(timezone))
+ timezone = "UTC";
+ TimeZone tz = TimeZone.getTimeZone(timezone);
+ if (tz == null)
+ return null;
+ cal.set(Calendar.ZONE_OFFSET, tz.getRawOffset());
+ }
+ else
+ {
+ String tzh = timezone.substring(0, i);
+ String tzm = timezone.substring(i + 1);
+ int offset = Integer.parseInt(tzh) * 360000;
+ if (offset < 0)
+ offset -= Integer.parseInt(tzm) * 60000;
+ else
+ offset += Integer.parseInt(tzm) * 60000;
+ cal.set(Calendar.ZONE_OFFSET, offset);
+ }
+ }
+ return cal.getTime();
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/DecimalType.java b/libjava/classpath/gnu/xml/validation/datatype/DecimalType.java
new file mode 100644
index 000000000..43a26a399
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/DecimalType.java
@@ -0,0 +1,118 @@
+/* DecimalType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.math.BigDecimal;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema decimal type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class DecimalType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.TOTAL_DIGITS,
+ Facet.FRACTION_DIGITS,
+ Facet.PATTERN,
+ Facet.WHITESPACE,
+ Facet.ENUMERATION,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ DecimalType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "decimal"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException("invalid decimal value");
+ boolean seenDot = false;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c >= 0x30 && c <= 0x39)
+ continue;
+ else if (c == '.')
+ {
+ if (seenDot)
+ throw new DatatypeException(i, "invalid decimal value");
+ seenDot = true;
+ continue;
+ }
+ else if (c == '+' && i == 0)
+ continue;
+ else if (c == '-' && i == 0)
+ continue;
+ else
+ throw new DatatypeException(i, "invalid decimal value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new BigDecimal(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/DoubleType.java b/libjava/classpath/gnu/xml/validation/datatype/DoubleType.java
new file mode 100644
index 000000000..dfaa7c8cb
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/DoubleType.java
@@ -0,0 +1,110 @@
+/* DoubleType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema double type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class DoubleType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ static final Set SPECIAL =
+ new TreeSet(Arrays.asList(new String[] {"INF", "-INF", "NaN"}));
+
+ DoubleType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "double"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ if (SPECIAL.contains(value))
+ return;
+ try
+ {
+ Double.parseDouble(value);
+ }
+ catch (NumberFormatException e)
+ {
+ DatatypeException e2 = new DatatypeException("invalid double value");
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new Double(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/DurationType.java b/libjava/classpath/gnu/xml/validation/datatype/DurationType.java
new file mode 100644
index 000000000..6c0f7b889
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/DurationType.java
@@ -0,0 +1,238 @@
+/* DurationType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema duration type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class DurationType
+ extends AtomicSimpleType
+{
+
+ static class Duration
+ implements Comparable
+ {
+ int years;
+ int months;
+ int days;
+ int minutes;
+ float seconds;
+
+ public int hashCode()
+ {
+ int hc = years;
+ hc = hc * 31 + months;
+ hc = hc * 31 + days;
+ hc = hc * 31 + minutes;
+ hc = hc * 31 + new Float(seconds).hashCode();
+ return hc;
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other instanceof Duration)
+ {
+ Duration duration = (Duration) other;
+ return duration.years ==years &&
+ duration.months == months &&
+ duration.days == days &&
+ duration.minutes == minutes &&
+ duration.seconds == seconds;
+ }
+ return false;
+ }
+
+ public int compareTo(Object other)
+ {
+ if (other instanceof Duration)
+ {
+ Duration duration = (Duration) other;
+ if (duration.years != years)
+ return years - duration.years;
+ if (duration.months != months)
+ return months - duration.months;
+ if (duration.days != days)
+ return days - duration.days;
+ if (duration.minutes != minutes)
+ return minutes = duration.minutes;
+ if (duration.seconds == seconds)
+ return 0;
+ return (seconds < duration.seconds) ? -1 : 1;
+ }
+ return 0;
+ }
+
+ }
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ DurationType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "duration"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ char expect = 'P';
+ boolean seenT = false;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == '-' && expect == 'P')
+ continue;
+ if (c == expect)
+ {
+ if (c == 'P')
+ expect = 'Y';
+ else if (c == 'Y')
+ expect = 'M';
+ else if (c == 'M' && !seenT)
+ expect = 'D';
+ else if (c == 'D')
+ expect = 'T';
+ else if (c == 'T')
+ {
+ expect = 'H';
+ seenT = true;
+ }
+ else if (c == 'H')
+ expect = 'M';
+ else if (c == 'M' && seenT)
+ expect = 'S';
+ else if (c == 'S')
+ {
+ if (i + 1 != len)
+ throw new DatatypeException(i, "illegal duration value");
+ }
+ continue;
+ }
+ if (c >= 0x30 && c <= 0x39 && expect != 'P' && expect != 'T')
+ continue;
+ throw new DatatypeException(i, "illegal duration value");
+ }
+ }
+
+ public Object createValue(String value, ValidationContext context) {
+ boolean negative = false;
+ int days = 0, months = 0, years = 0;
+ int minutes = 0;
+ float seconds = 0.0f;
+ int len = value.length();
+ char expect = 'P';
+ boolean seenT = false;
+ int start = 0;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == '-' && expect == 'P')
+ {
+ negative = true;
+ continue;
+ }
+ if (c == expect)
+ {
+ if (c == 'P')
+ expect = 'Y';
+ else if (c == 'Y')
+ {
+ expect = 'M';
+ years = Integer.parseInt(value.substring(start, i));
+ }
+ else if (c == 'M' && !seenT)
+ expect = 'D';
+ else if (c == 'D')
+ expect = 'T';
+ else if (c == 'T')
+ {
+ expect = 'H';
+ seenT = true;
+ }
+ else if (c == 'H')
+ expect = 'M';
+ else if (c == 'M' && seenT)
+ expect = 'S';
+ else if (c == 'S')
+ {
+ if (i + 1 != len)
+ return null;
+ }
+ start = i + 1;
+ continue;
+ }
+ if (c >= 0x30 && c <= 0x39 && expect != 'P' && expect != 'T')
+ continue;
+ return null;
+ }
+ if (negative)
+ {
+ days = days * -1;
+ minutes = minutes * -1;
+ seconds = seconds * -1.0f;
+ }
+ Duration duration = new Duration();
+ duration.days = days;
+ duration.minutes = minutes;
+ duration.seconds = seconds;
+ return duration;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/EntitiesType.java b/libjava/classpath/gnu/xml/validation/datatype/EntitiesType.java
new file mode 100644
index 000000000..5415e88e2
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/EntitiesType.java
@@ -0,0 +1,108 @@
+/* EntitiesType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import gnu.java.lang.CPStringBuilder;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema ENTITIES type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class EntitiesType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ EntitiesType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "ENTITIES"),
+ TypeLibrary.ENTITY);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ CPStringBuilder buf = new CPStringBuilder();
+ int len = value.length();
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == ' ')
+ {
+ String token = buf.toString();
+ if (token.length() > 0)
+ {
+ if (!context.isUnparsedEntity(token))
+ throw new DatatypeException(i, "invalid ENTITIES value");
+ }
+ buf.setLength(0);
+ }
+ else
+ buf.append(c);
+ }
+ String token = buf.toString();
+ if (token.length() == 0 || !context.isUnparsedEntity(token))
+ throw new DatatypeException("invalid ENTITIES value");
+ }
+
+ public boolean isContextDependent()
+ {
+ return true;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/EntityType.java b/libjava/classpath/gnu/xml/validation/datatype/EntityType.java
new file mode 100644
index 000000000..f4a10bd50
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/EntityType.java
@@ -0,0 +1,87 @@
+/* EntityType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema ENTITY type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class EntityType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ EntityType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "ENTITY"),
+ TypeLibrary.NCNAME);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ if (value.length() == 0 || !context.isUnparsedEntity(value))
+ throw new DatatypeException("invalid ENTITY value");
+ }
+
+ public boolean isContextDependent()
+ {
+ return true;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/EnumerationFacet.java b/libjava/classpath/gnu/xml/validation/datatype/EnumerationFacet.java
new file mode 100644
index 000000000..45b9c2378
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/EnumerationFacet.java
@@ -0,0 +1,68 @@
+/* EnumerationFacet.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+/**
+ * The <code>enumeration</code> facet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class EnumerationFacet
+ extends Facet
+{
+
+ public final String value;
+
+ public EnumerationFacet(String value, Annotation annotation)
+ {
+ super(ENUMERATION, annotation);
+ this.value = value;
+ }
+
+ public int hashCode()
+ {
+ return value.hashCode();
+ }
+
+ public boolean equals(Object other)
+ {
+ return (other instanceof EnumerationFacet &&
+ ((EnumerationFacet) other).value.equals(value));
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/Facet.java b/libjava/classpath/gnu/xml/validation/datatype/Facet.java
new file mode 100644
index 000000000..9f18bedc8
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/Facet.java
@@ -0,0 +1,77 @@
+/* Facet.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+/**
+ * An XML Schema constraining facet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public abstract class Facet
+{
+
+ public static final int LENGTH = 1;
+ public static final int MIN_LENGTH = 2;
+ public static final int MAX_LENGTH = 3;
+ public static final int PATTERN = 4;
+ public static final int ENUMERATION = 5;
+ public static final int WHITESPACE = 6;
+ public static final int MAX_INCLUSIVE = 7;
+ public static final int MAX_EXCLUSIVE = 8;
+ public static final int MIN_EXCLUSIVE = 9;
+ public static final int MIN_INCLUSIVE = 10;
+ public static final int TOTAL_DIGITS = 11;
+ public static final int FRACTION_DIGITS = 12;
+
+ /**
+ * The type of this facet.
+ */
+ public final int type;
+
+ /**
+ * Optional annotation.
+ */
+ public Annotation annotation;
+
+ protected Facet(int type, Annotation annotation)
+ {
+ this.type = type;
+ this.annotation = annotation;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/FloatType.java b/libjava/classpath/gnu/xml/validation/datatype/FloatType.java
new file mode 100644
index 000000000..8dbb4aa56
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/FloatType.java
@@ -0,0 +1,110 @@
+/* FloatType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.Arrays;
+import java.util.Set;
+import java.util.TreeSet;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema float type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class FloatType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ static final Set SPECIAL =
+ new TreeSet(Arrays.asList(new String[] {"INF", "-INF", "NaN"}));
+
+ FloatType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "float"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ if (SPECIAL.contains(value))
+ return;
+ try
+ {
+ Float.parseFloat(value);
+ }
+ catch (NumberFormatException e)
+ {
+ DatatypeException e2 = new DatatypeException("invalid float value");
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new Float(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/FractionDigitsFacet.java b/libjava/classpath/gnu/xml/validation/datatype/FractionDigitsFacet.java
new file mode 100644
index 000000000..c0d714578
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/FractionDigitsFacet.java
@@ -0,0 +1,71 @@
+/* FractionDigitsFacet.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+/**
+ * The <code>fractionDigits</code> facet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class FractionDigitsFacet
+ extends Facet
+{
+
+ public final int value;
+
+ public final boolean fixed;
+
+ public FractionDigitsFacet(int value, boolean fixed, Annotation annotation)
+ {
+ super(FRACTION_DIGITS, annotation);
+ this.value = value;
+ this.fixed = fixed;
+ }
+
+ public int hashCode()
+ {
+ return value;
+ }
+
+ public boolean equals(Object other)
+ {
+ return (other instanceof FractionDigitsFacet &&
+ ((FractionDigitsFacet) other).value == value);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/GDayType.java b/libjava/classpath/gnu/xml/validation/datatype/GDayType.java
new file mode 100644
index 000000000..cc6b8e3d4
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/GDayType.java
@@ -0,0 +1,174 @@
+/* GDayType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema gDay type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class GDayType
+ extends AtomicSimpleType
+{
+
+ static class GDay
+ implements Comparable
+ {
+
+ int day;
+
+ public int hashCode()
+ {
+ return day;
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other instanceof GDay)
+ return ((GDay) other).day == day;
+ return false;
+ }
+
+ public int compareTo(Object other)
+ {
+ if (other instanceof GDay)
+ {
+ GDay gd = (GDay) other;
+ if (gd.day == day)
+ return 0;
+ return (day < gd.day) ? -1 : 1;
+ }
+ return 0;
+ }
+
+ }
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ GDayType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gDay"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ int state = 0;
+ int start = 0;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c >= 0x30 && c <= 0x39)
+ continue;
+ switch (state)
+ {
+ case 0: // year
+ if (c == '-')
+ {
+ switch (i)
+ {
+ case 0:
+ continue;
+ case 1:
+ state = 1;
+ start = i + 1;
+ continue;
+ default:
+ throw new DatatypeException(i, "invalid GDay value");
+ }
+ }
+ break;
+ case 1: // month
+ if (c == '-')
+ {
+ if (i - start != 0)
+ throw new DatatypeException(i, "invalid GDay value");
+ state = 2;
+ start = i + 1;
+ continue;
+ }
+ break;
+ }
+ throw new DatatypeException(i, "invalid GDay value");
+ }
+ switch (state)
+ {
+ case 2: // day
+ if (len - start != 2)
+ throw new DatatypeException("invalid GDay value");
+ break;
+ default:
+ throw new DatatypeException("invalid GDay value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ GDay ret = new GDay();
+ ret.day = Integer.parseInt(literal.substring(3));
+ return ret;
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/GMonthDayType.java b/libjava/classpath/gnu/xml/validation/datatype/GMonthDayType.java
new file mode 100644
index 000000000..d293d9b57
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/GMonthDayType.java
@@ -0,0 +1,183 @@
+/* GMonthDayType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema gMonthDay type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class GMonthDayType
+ extends AtomicSimpleType
+{
+
+ static class GMonthDay
+ implements Comparable
+ {
+
+ int month;
+ int day;
+
+ public int hashCode()
+ {
+ return month * 31 + day;
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other instanceof GMonthDay)
+ {
+ GMonthDay gmd = (GMonthDay) other;
+ return gmd.month == month && gmd.day == day;
+ }
+ return false;
+ }
+
+ public int compareTo(Object other)
+ {
+ if (other instanceof GMonthDay)
+ {
+ GMonthDay gmd = (GMonthDay) other;
+ if (gmd.month == month)
+ {
+ if (gmd.day == day)
+ return 0;
+ return (day < gmd.day) ? -1 : 1;
+ }
+ return (month < gmd.month) ? -1 : 1;
+ }
+ return 0;
+ }
+
+ }
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ GMonthDayType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gMonthDay"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ int state = 0;
+ int start = 0;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c >= 0x30 && c <= 0x39)
+ continue;
+ switch (state)
+ {
+ case 0: // year
+ if (c == '-')
+ {
+ switch (i)
+ {
+ case 0:
+ continue;
+ case 1:
+ state = 1;
+ start = i + 1;
+ continue;
+ default:
+ throw new DatatypeException(i, "illegal GMonthDay type");
+ }
+ }
+ break;
+ case 1: // month
+ if (c == '-')
+ {
+ if (i - start != 2)
+ throw new DatatypeException(i, "illegal GMonthDay type");
+ state = 2;
+ start = i + 1;
+ continue;
+ }
+ break;
+ }
+ throw new DatatypeException(i, "illegal GMonthDay type");
+ }
+ switch (state)
+ {
+ case 2: // day
+ if (len - start != 2)
+ throw new DatatypeException("illegal GMonthDay type");
+ break;
+ default:
+ throw new DatatypeException("illegal GMonthDay type");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ GMonthDay ret = new GMonthDay();
+ ret.month = Integer.parseInt(literal.substring(2, 5));
+ ret.day = Integer.parseInt(literal.substring(6));
+ return ret;
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/GMonthType.java b/libjava/classpath/gnu/xml/validation/datatype/GMonthType.java
new file mode 100644
index 000000000..9450874b9
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/GMonthType.java
@@ -0,0 +1,163 @@
+/* GMonthType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema gMonth type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class GMonthType
+ extends AtomicSimpleType
+{
+
+ static class GMonth
+ implements Comparable
+ {
+
+ int month;
+
+ public int hashCode()
+ {
+ return month;
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other instanceof GMonth)
+ return ((GMonth) other).month == month;
+ return false;
+ }
+
+ public int compareTo(Object other)
+ {
+ if (other instanceof GMonth)
+ {
+ GMonth gm = (GMonth) other;
+ if (gm.month == month)
+ return 0;
+ return (month < gm.month) ? -1 : 1;
+ }
+ return 0;
+ }
+
+ }
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ GMonthType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gMonth"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ int len = value.length();
+ int state = 0;
+ int start = 0;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c >= 0x30 && c <= 0x39)
+ continue;
+ switch (state)
+ {
+ case 0: // year
+ if (c == '-')
+ {
+ switch (i)
+ {
+ case 0:
+ continue;
+ case 1:
+ state = 1;
+ start = i + 1;
+ continue;
+ default:
+ throw new DatatypeException(i, "illegal GMonth value");
+ }
+ }
+ break;
+ }
+ throw new DatatypeException(i, "illegal GMonth value");
+ }
+ switch (state)
+ {
+ case 1: // month
+ if (len - start != 2)
+ throw new DatatypeException("illegal GMonth value");
+ break;
+ default:
+ throw new DatatypeException("illegal GMonth value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ GMonth ret = new GMonth();
+ ret.month = Integer.parseInt(literal.substring(2));
+ return ret;
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/GYearMonthType.java b/libjava/classpath/gnu/xml/validation/datatype/GYearMonthType.java
new file mode 100644
index 000000000..9aabfb61c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/GYearMonthType.java
@@ -0,0 +1,176 @@
+/* GYearMonthType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema gYearMonth type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class GYearMonthType
+ extends AtomicSimpleType
+{
+
+ static class GYearMonth
+ implements Comparable
+ {
+
+ int year;
+ int month;
+
+ public int hashCode()
+ {
+ return year * 31 + month;
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other instanceof GYearMonth)
+ {
+ GYearMonth gmy = (GYearMonth) other;
+ return gmy.year == year && gmy.month == month;
+ }
+ return false;
+ }
+
+ public int compareTo(Object other)
+ {
+ if (other instanceof GYearMonth)
+ {
+ GYearMonth gmy = (GYearMonth) other;
+ if (gmy.year == year)
+ {
+ if (gmy.month == month)
+ return 0;
+ return (month < gmy.month) ? -1 : 1;
+ }
+ return (year < gmy.year) ? -1 : 1;
+ }
+ return 0;
+ }
+
+ }
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ GYearMonthType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gYearMonth"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ int state = 0;
+ int start = 0;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == '-' && i == 0)
+ {
+ start++;
+ continue;
+ }
+ if (c >= 0x30 && c <= 0x39)
+ continue;
+ switch (state)
+ {
+ case 0: // year
+ if (c == '-')
+ {
+ String year = value.substring(start, i);
+ if (year.length() < 4 || Integer.parseInt(year) == 0)
+ throw new DatatypeException(i, "illegal GYear value");
+ state = 1;
+ start = i + 1;
+ continue;
+ }
+ break;
+ }
+ throw new DatatypeException(i, "illegal GYear value");
+ }
+ switch (state)
+ {
+ case 1: // month
+ if (len - start != 2)
+ throw new DatatypeException("illegal GYear value");
+ break;
+ default:
+ throw new DatatypeException("illegal GYear value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ int offset = 5;
+ if (literal.charAt(0) == '-')
+ offset++;
+ GYearMonth ret = new GYearMonth();
+ ret.year = Integer.parseInt(literal.substring(0, offset));
+ ret.month = Integer.parseInt(literal.substring(offset + 1));
+ return ret;
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/GYearType.java b/libjava/classpath/gnu/xml/validation/datatype/GYearType.java
new file mode 100644
index 000000000..5b1e03232
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/GYearType.java
@@ -0,0 +1,151 @@
+/* GYearType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema gYear type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class GYearType
+ extends AtomicSimpleType
+{
+
+ static class GYear
+ implements Comparable
+ {
+
+ int year;
+
+ public int hashCode()
+ {
+ return year;
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other instanceof GYear)
+ return ((GYear) other).year == year;
+ return false;
+ }
+
+ public int compareTo(Object other)
+ {
+ if (other instanceof GYear)
+ {
+ GYear gy = (GYear) other;
+ if (gy.year == year)
+ return 0;
+ return (year < gy.year) ? -1 : 1;
+ }
+ return 0;
+ }
+
+ }
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ GYearType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "gYear"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ int state = 0;
+ int start = 0;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == '-' && i == 0)
+ {
+ start++;
+ continue;
+ }
+ if (c >= 0x30 && c <= 0x39)
+ continue;
+ throw new DatatypeException(i, "invalid GYear value");
+ }
+ switch (state)
+ {
+ case 0: // year
+ String year = value.substring(start, len);
+ if (year.length() < 4 || Integer.parseInt(year) == 0)
+ throw new DatatypeException("invalid GYear value");
+ break;
+ default:
+ throw new DatatypeException("invalid GYear value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ GYear ret = new GYear();
+ ret.year = Integer.parseInt(literal);
+ return ret;
+ }
+ catch (Exception e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/HexBinaryType.java b/libjava/classpath/gnu/xml/validation/datatype/HexBinaryType.java
new file mode 100644
index 000000000..5f133e322
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/HexBinaryType.java
@@ -0,0 +1,89 @@
+/* HexBinaryType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema hexBinary type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class HexBinaryType
+ extends AtomicSimpleType
+{
+
+ static final String HEX = "0123456789ABCDEF";
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ HexBinaryType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "hexBinary"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (HEX.indexOf(c) == -1)
+ throw new DatatypeException(i, "invalid hexBinary value");
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/IDRefType.java b/libjava/classpath/gnu/xml/validation/datatype/IDRefType.java
new file mode 100644
index 000000000..932089549
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/IDRefType.java
@@ -0,0 +1,86 @@
+/* IDRefType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema IDREF type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class IDRefType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ IDRefType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "IDREF"),
+ TypeLibrary.NCNAME);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ // TODO
+ }
+
+ public int getIdType()
+ {
+ return ID_TYPE_IDREF;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/IDRefsType.java b/libjava/classpath/gnu/xml/validation/datatype/IDRefsType.java
new file mode 100644
index 000000000..6adaed13b
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/IDRefsType.java
@@ -0,0 +1,86 @@
+/* IDRefsType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema IDREFS type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class IDRefsType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ IDRefsType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "IDREFS"),
+ TypeLibrary.IDREF);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ // TODO
+ }
+
+ public int getIdType()
+ {
+ return ID_TYPE_IDREFS;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/IDType.java b/libjava/classpath/gnu/xml/validation/datatype/IDType.java
new file mode 100644
index 000000000..792601d78
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/IDType.java
@@ -0,0 +1,86 @@
+/* IDType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema ID type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class IDType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ IDType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "ID"),
+ TypeLibrary.NCNAME);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ // TODO
+ }
+
+ public int getIdType()
+ {
+ return ID_TYPE_ID;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/IntType.java b/libjava/classpath/gnu/xml/validation/datatype/IntType.java
new file mode 100644
index 000000000..c8f756832
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/IntType.java
@@ -0,0 +1,132 @@
+/* IntType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema int type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class IntType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.TOTAL_DIGITS,
+ Facet.FRACTION_DIGITS,
+ Facet.PATTERN,
+ Facet.WHITESPACE,
+ Facet.ENUMERATION,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ static final String MAX_VALUE = "2147483647";
+ static final String MIN_VALUE = "2147483648";
+ static final int LENGTH = MAX_VALUE.length();
+
+ IntType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "int"),
+ TypeLibrary.LONG);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException(0, "invalid int value");
+ int i = 0, off = 0;
+ boolean compare = false;
+ String compareTo = MAX_VALUE;
+ char c = value.charAt(0);
+ if (c == '+')
+ i++;
+ else if (c == '-')
+ {
+ compareTo = MIN_VALUE;
+ i++;
+ }
+ if (len - i > LENGTH)
+ throw new DatatypeException("invalid int value");
+ else if (len - i == LENGTH)
+ compare = true;
+ for (; i < len; i++)
+ {
+ c = value.charAt(i);
+ if (c >= 0x30 && c <= 0x39)
+ {
+ if (compare)
+ {
+ char d = compareTo.charAt(off);
+ if (Character.digit(c, 10) > Character.digit(d, 10))
+ throw new DatatypeException(i, "invalid int value");
+ }
+ off++;
+ continue;
+ }
+ throw new DatatypeException(i, "invalid int value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new Integer(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/IntegerType.java b/libjava/classpath/gnu/xml/validation/datatype/IntegerType.java
new file mode 100644
index 000000000..b9a2a564a
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/IntegerType.java
@@ -0,0 +1,109 @@
+/* IntegerType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.math.BigInteger;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema integer type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class IntegerType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.TOTAL_DIGITS,
+ Facet.FRACTION_DIGITS,
+ Facet.PATTERN,
+ Facet.WHITESPACE,
+ Facet.ENUMERATION,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ IntegerType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "integer"),
+ TypeLibrary.DECIMAL);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException(0, "invalid integer value");
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c >= 0x30 && c <= 0x39)
+ continue;
+ else if (c == '+' && i == 0)
+ continue;
+ else if (c == '-' && i == 0)
+ continue;
+ throw new DatatypeException(i, "invalid integer value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new BigInteger(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/LanguageType.java b/libjava/classpath/gnu/xml/validation/datatype/LanguageType.java
new file mode 100644
index 000000000..d30cc538f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/LanguageType.java
@@ -0,0 +1,86 @@
+/* LanguageType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.regex.Pattern;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema language type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class LanguageType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ static final Pattern PATTERN =
+ Pattern.compile("[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*");
+
+ LanguageType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "language"),
+ TypeLibrary.TOKEN);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ if (!PATTERN.matcher(value).matches())
+ throw new DatatypeException("invalid language value");
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/LengthFacet.java b/libjava/classpath/gnu/xml/validation/datatype/LengthFacet.java
new file mode 100644
index 000000000..d6eaacd71
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/LengthFacet.java
@@ -0,0 +1,71 @@
+/* LengthFacet.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+/**
+ * The <code>length</code> facet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class LengthFacet
+ extends Facet
+{
+
+ public final int value;
+
+ public final boolean fixed;
+
+ public LengthFacet(int value, boolean fixed, Annotation annotation)
+ {
+ super(LENGTH, annotation);
+ this.value = value;
+ this.fixed = fixed;
+ }
+
+ public int hashCode()
+ {
+ return value;
+ }
+
+ public boolean equals(Object other)
+ {
+ return (other instanceof LengthFacet &&
+ ((LengthFacet) other).value == value);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/ListSimpleType.java b/libjava/classpath/gnu/xml/validation/datatype/ListSimpleType.java
new file mode 100644
index 000000000..1e0d41d01
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/ListSimpleType.java
@@ -0,0 +1,82 @@
+/* ListSimpleType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.Set;
+import java.util.StringTokenizer;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * An XML Schema list simple type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class ListSimpleType
+ extends SimpleType
+{
+
+ /**
+ * The type of the items in this list (atomic or union).
+ */
+ public final SimpleType itemType;
+
+ public ListSimpleType(QName name, Set facets,
+ int fundamentalFacets, SimpleType baseType,
+ Annotation annotation, SimpleType itemType)
+ {
+ super(name, LIST, facets, fundamentalFacets, baseType, annotation);
+ this.itemType = itemType;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ StringTokenizer st = new StringTokenizer(value, " ");
+ if (!st.hasMoreTokens())
+ throw new DatatypeException("invalid list value");
+ while (st.hasMoreTokens())
+ {
+ String token = st.nextToken();
+ itemType.checkValid(token, context);
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/LongType.java b/libjava/classpath/gnu/xml/validation/datatype/LongType.java
new file mode 100644
index 000000000..781b17f62
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/LongType.java
@@ -0,0 +1,132 @@
+/* LongType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema long type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class LongType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.TOTAL_DIGITS,
+ Facet.FRACTION_DIGITS,
+ Facet.PATTERN,
+ Facet.WHITESPACE,
+ Facet.ENUMERATION,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ static final String MAX_VALUE = "9223372036854775807";
+ static final String MIN_VALUE = "9223372036854775808";
+ static final int LENGTH = MAX_VALUE.length();
+
+ LongType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "long"),
+ TypeLibrary.INTEGER);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException(0, "invalid long value");
+ int i = 0, off = 0;
+ boolean compare = false;
+ String compareTo = MAX_VALUE;
+ char c = value.charAt(0);
+ if (c == '+')
+ i++;
+ else if (c == '-')
+ {
+ compareTo = MIN_VALUE;
+ i++;
+ }
+ if (len - i > LENGTH)
+ throw new DatatypeException(i, "invalid long value");
+ else if (len - i == LENGTH)
+ compare = true;
+ for (; i < len; i++)
+ {
+ c = value.charAt(i);
+ if (c >= 0x30 && c <= 0x39)
+ {
+ if (compare)
+ {
+ char d = compareTo.charAt(off);
+ if (Character.digit(c, 10) > Character.digit(d, 10))
+ throw new DatatypeException(i, "invalid long value");
+ }
+ off++;
+ continue;
+ }
+ throw new DatatypeException(i, "invalid long value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new Long(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/MaxExclusiveFacet.java b/libjava/classpath/gnu/xml/validation/datatype/MaxExclusiveFacet.java
new file mode 100644
index 000000000..90e940371
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/MaxExclusiveFacet.java
@@ -0,0 +1,110 @@
+/* MaxExclusiveFacet.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * The <code>maxExclusive</code> facet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class MaxExclusiveFacet
+ extends Facet
+{
+
+ public final Object value; // date or number
+
+ public final boolean fixed;
+
+ public MaxExclusiveFacet(Object value, boolean fixed, Annotation annotation)
+ {
+ super(MAX_EXCLUSIVE, annotation);
+ this.value = value;
+ this.fixed = fixed;
+ }
+
+ public int hashCode()
+ {
+ return value.hashCode();
+ }
+
+ public boolean equals(Object other)
+ {
+ return (other instanceof MaxExclusiveFacet &&
+ ((MaxExclusiveFacet) other).value.equals(value));
+ }
+
+ boolean matches(Object test)
+ {
+ if (value instanceof Date)
+ {
+ Date dvalue = (Date) value;
+ if (!(test instanceof Date))
+ return false;
+ return ((Date) test).before(dvalue);
+ }
+ else if (value instanceof BigInteger)
+ {
+ BigInteger ivalue = (BigInteger) value;
+ if (!(test instanceof BigInteger))
+ return false;
+ return ((BigInteger) test).compareTo(ivalue) < 0;
+ }
+ else if (value instanceof BigDecimal)
+ {
+ BigDecimal dvalue = (BigDecimal) value;
+ if (!(test instanceof BigDecimal))
+ return false;
+ return ((BigDecimal) test).compareTo(dvalue) < 0;
+ }
+ else if (value instanceof Comparable)
+ {
+ if (!(test.getClass().equals(value.getClass())))
+ return false;
+ return ((Comparable) test).compareTo(value) < 0;
+ }
+ Number nvalue = (Number) value;
+ if (!(test instanceof Number))
+ return false;
+ return ((Number) test).doubleValue() < nvalue.doubleValue();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/MaxInclusiveFacet.java b/libjava/classpath/gnu/xml/validation/datatype/MaxInclusiveFacet.java
new file mode 100644
index 000000000..c260113da
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/MaxInclusiveFacet.java
@@ -0,0 +1,111 @@
+/* MaxInclusiveFacet.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * The <code>maxInclusive</code> facet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class MaxInclusiveFacet
+ extends Facet
+{
+
+ public final Object value;
+
+ public final boolean fixed;
+
+ public MaxInclusiveFacet(Object value, boolean fixed, Annotation annotation)
+ {
+ super(MAX_INCLUSIVE, annotation);
+ this.value = value;
+ this.fixed = fixed;
+ }
+
+ public int hashCode()
+ {
+ return value.hashCode();
+ }
+
+ public boolean equals(Object other)
+ {
+ return (other instanceof MaxInclusiveFacet &&
+ ((MaxInclusiveFacet) other).value.equals(value));
+ }
+
+ boolean matches(Object test)
+ {
+ if (value instanceof Date)
+ {
+ Date dvalue = (Date) value;
+ if (!(test instanceof Date))
+ return false;
+ Date dtest = (Date) test;
+ return dtest.equals(dvalue) || dtest.before(dvalue);
+ }
+ else if (value instanceof BigInteger)
+ {
+ BigInteger ivalue = (BigInteger) value;
+ if (!(test instanceof BigInteger))
+ return false;
+ return ((BigInteger) test).compareTo(ivalue) <= 0;
+ }
+ else if (value instanceof BigDecimal)
+ {
+ BigDecimal dvalue = (BigDecimal) value;
+ if (!(test instanceof BigDecimal))
+ return false;
+ return ((BigDecimal) test).compareTo(dvalue) <= 0;
+ }
+ else if (value instanceof Comparable)
+ {
+ if (!(test.getClass().equals(value.getClass())))
+ return false;
+ return ((Comparable) test).compareTo(value) <= 0;
+ }
+ Number nvalue = (Number) value;
+ if (!(test instanceof Number))
+ return false;
+ return ((Number) test).doubleValue() <= nvalue.doubleValue();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/MaxLengthFacet.java b/libjava/classpath/gnu/xml/validation/datatype/MaxLengthFacet.java
new file mode 100644
index 000000000..ba77ff2df
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/MaxLengthFacet.java
@@ -0,0 +1,71 @@
+/* MaxLengthFacet.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+/**
+ * The <code>maxLength</code> facet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class MaxLengthFacet
+ extends Facet
+{
+
+ public final int value;
+
+ public final boolean fixed;
+
+ public MaxLengthFacet(int value, boolean fixed, Annotation annotation)
+ {
+ super(MAX_LENGTH, annotation);
+ this.value = value;
+ this.fixed = fixed;
+ }
+
+ public int hashCode()
+ {
+ return value;
+ }
+
+ public boolean equals(Object other)
+ {
+ return (other instanceof MaxLengthFacet &&
+ ((MaxLengthFacet) other).value == value);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/MinExclusiveFacet.java b/libjava/classpath/gnu/xml/validation/datatype/MinExclusiveFacet.java
new file mode 100644
index 000000000..a779d09d8
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/MinExclusiveFacet.java
@@ -0,0 +1,110 @@
+/* MinExclusiveFacet.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * The <code>minExclusive</code> facet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class MinExclusiveFacet
+ extends Facet
+{
+
+ public final Object value;
+
+ public final boolean fixed;
+
+ public MinExclusiveFacet(Object value, boolean fixed, Annotation annotation)
+ {
+ super(MIN_EXCLUSIVE, annotation);
+ this.value = value;
+ this.fixed = fixed;
+ }
+
+ public int hashCode()
+ {
+ return value.hashCode();
+ }
+
+ public boolean equals(Object other)
+ {
+ return (other instanceof MinExclusiveFacet &&
+ ((MinExclusiveFacet) other).value.equals(value));
+ }
+
+ boolean matches(Object test)
+ {
+ if (value instanceof Date)
+ {
+ Date dvalue = (Date) value;
+ if (!(test instanceof Date))
+ return false;
+ return ((Date) test).after(dvalue);
+ }
+ else if (value instanceof BigInteger)
+ {
+ BigInteger ivalue = (BigInteger) value;
+ if (!(test instanceof BigInteger))
+ return false;
+ return ((BigInteger) test).compareTo(ivalue) > 0;
+ }
+ else if (value instanceof BigDecimal)
+ {
+ BigDecimal dvalue = (BigDecimal) value;
+ if (!(test instanceof BigDecimal))
+ return false;
+ return ((BigDecimal) test).compareTo(dvalue) > 0;
+ }
+ else if (value instanceof Comparable)
+ {
+ if (!(test.getClass().equals(value.getClass())))
+ return false;
+ return ((Comparable) test).compareTo(value) > 0;
+ }
+ Number nvalue = (Number) value;
+ if (!(test instanceof Number))
+ return false;
+ return ((Number) test).doubleValue() > nvalue.doubleValue();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/MinInclusiveFacet.java b/libjava/classpath/gnu/xml/validation/datatype/MinInclusiveFacet.java
new file mode 100644
index 000000000..6138c9af8
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/MinInclusiveFacet.java
@@ -0,0 +1,111 @@
+/* MinInclusiveFacet.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * The <code>minInclusive</code> facet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class MinInclusiveFacet
+ extends Facet
+{
+
+ public final Object value;
+
+ public final boolean fixed;
+
+ public MinInclusiveFacet(Object value, boolean fixed, Annotation annotation)
+ {
+ super(MIN_INCLUSIVE, annotation);
+ this.value = value;
+ this.fixed = fixed;
+ }
+
+ public int hashCode()
+ {
+ return value.hashCode();
+ }
+
+ public boolean equals(Object other)
+ {
+ return (other instanceof MinInclusiveFacet &&
+ ((MinInclusiveFacet) other).value.equals(value));
+ }
+
+ boolean matches(Object test)
+ {
+ if (value instanceof Date)
+ {
+ Date dvalue = (Date) value;
+ if (!(test instanceof Date))
+ return false;
+ Date dtest = (Date) test;
+ return dtest.equals(dvalue) || dtest.after(dvalue);
+ }
+ else if (value instanceof BigInteger)
+ {
+ BigInteger ivalue = (BigInteger) value;
+ if (!(test instanceof BigInteger))
+ return false;
+ return ((BigInteger) test).compareTo(ivalue) >= 0;
+ }
+ else if (value instanceof BigDecimal)
+ {
+ BigDecimal dvalue = (BigDecimal) value;
+ if (!(test instanceof BigDecimal))
+ return false;
+ return ((BigDecimal) test).compareTo(dvalue) >= 0;
+ }
+ else if (value instanceof Comparable)
+ {
+ if (!(test.getClass().equals(value.getClass())))
+ return false;
+ return ((Comparable) test).compareTo(value) >= 0;
+ }
+ Number nvalue = (Number) value;
+ if (!(test instanceof Number))
+ return false;
+ return ((Number) test).doubleValue() >= nvalue.doubleValue();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/MinLengthFacet.java b/libjava/classpath/gnu/xml/validation/datatype/MinLengthFacet.java
new file mode 100644
index 000000000..f13e80b62
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/MinLengthFacet.java
@@ -0,0 +1,71 @@
+/* MinLengthFacet.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+/**
+ * The <code>minLength</code> facet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class MinLengthFacet
+ extends Facet
+{
+
+ public final int value;
+
+ public final boolean fixed;
+
+ public MinLengthFacet(int value, boolean fixed, Annotation annotation)
+ {
+ super(MIN_LENGTH, annotation);
+ this.value = value;
+ this.fixed = fixed;
+ }
+
+ public int hashCode()
+ {
+ return value;
+ }
+
+ public boolean equals(Object other)
+ {
+ return (other instanceof MinLengthFacet &&
+ ((MinLengthFacet) other).value == value);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/NCNameType.java b/libjava/classpath/gnu/xml/validation/datatype/NCNameType.java
new file mode 100644
index 000000000..3f2088f9b
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/NCNameType.java
@@ -0,0 +1,110 @@
+/* NCNameType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.io.IOException;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+import gnu.xml.stream.UnicodeReader;
+import gnu.xml.stream.XMLParser;
+
+/**
+ * The XML Schema NCName type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NCNameType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ NCNameType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "NCName"),
+ TypeLibrary.NAME);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ try
+ {
+ int[] cp = UnicodeReader.toCodePointArray(value);
+ if (cp.length == 0)
+ throw new DatatypeException("invalid NCName value");
+ // XXX XML 1.1 documents?
+ if (cp[0] == ':' || !XMLParser.isNameStartCharacter(cp[0], false))
+ throw new DatatypeException(0, "invalid NCName value");
+ boolean seenColon = false;
+ for (int i = 1; i < cp.length; i++)
+ {
+ if (cp[i] == ':')
+ {
+ if (seenColon || (i + 1 == cp.length))
+ throw new DatatypeException(i, "invalid NCName value");
+ seenColon = true;
+ }
+ else if (!XMLParser.isNameCharacter(cp[i], false))
+ throw new DatatypeException(i, "invalid NCName value");
+ }
+ }
+ catch (IOException e)
+ {
+ DatatypeException e2 = new DatatypeException("invalid NCName value");
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/NMTokenType.java b/libjava/classpath/gnu/xml/validation/datatype/NMTokenType.java
new file mode 100644
index 000000000..ca3271fef
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/NMTokenType.java
@@ -0,0 +1,101 @@
+/* NMTokenType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.io.IOException;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+import gnu.xml.stream.UnicodeReader;
+import gnu.xml.stream.XMLParser;
+
+/**
+ * The XML Schema NMTOKEN type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NMTokenType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ NMTokenType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "NMTOKEN"),
+ TypeLibrary.TOKEN);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ try
+ {
+ int[] cp = UnicodeReader.toCodePointArray(value);
+ if (cp.length == 0)
+ throw new DatatypeException("invalid NMTOKEN value");
+ for (int i = 0; i < cp.length; i++)
+ {
+ // XXX XML 1.1 documents?
+ if (!XMLParser.isNameCharacter(cp[i], false))
+ throw new DatatypeException(i, "invalid NMTOKEN value");
+ }
+ }
+ catch (IOException e)
+ {
+ DatatypeException e2 = new DatatypeException("invalid NMTOKEN value");
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/NMTokensType.java b/libjava/classpath/gnu/xml/validation/datatype/NMTokensType.java
new file mode 100644
index 000000000..388b451db
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/NMTokensType.java
@@ -0,0 +1,125 @@
+/* NMTokensType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.io.IOException;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+import gnu.xml.stream.UnicodeReader;
+import gnu.xml.stream.XMLParser;
+
+/**
+ * The XML Schema NMTOKENS type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NMTokensType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ NMTokensType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "NMTOKENS"),
+ TypeLibrary.NMTOKEN);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ CPStringBuilder buf = new CPStringBuilder();
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == ' ')
+ {
+ String token = buf.toString();
+ if (token.length() > 0)
+ checkNmtoken(token, i);
+ buf.setLength(0);
+ }
+ else
+ buf.append(c);
+ }
+ checkNmtoken(buf.toString(), len);
+ }
+
+ private void checkNmtoken(String text, int i)
+ throws DatatypeException
+ {
+ try
+ {
+ int[] cp = UnicodeReader.toCodePointArray(text);
+ if (cp.length == 0)
+ throw new DatatypeException("invalid NMTOKEN value");
+ for (int j = 0; j < cp.length; j++)
+ {
+ // XXX XML 1.1 documents?
+ if (!XMLParser.isNameCharacter(cp[j], false))
+ throw new DatatypeException(i, "invalid NMTOKEN value");
+ }
+ }
+ catch (IOException e)
+ {
+ DatatypeException e2 = new DatatypeException("invalid NMTOKEN value");
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/NameType.java b/libjava/classpath/gnu/xml/validation/datatype/NameType.java
new file mode 100644
index 000000000..70349aed8
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/NameType.java
@@ -0,0 +1,103 @@
+/* NameType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.io.IOException;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+import gnu.xml.stream.UnicodeReader;
+import gnu.xml.stream.XMLParser;
+
+/**
+ * The XML Schema Name type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NameType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ NameType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "Name"),
+ TypeLibrary.TOKEN);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ try
+ {
+ int[] cp = UnicodeReader.toCodePointArray(value);
+ if (cp.length == 0)
+ throw new DatatypeException("invalid Name value");
+ // XXX XML 1.1 documents?
+ if (!XMLParser.isNameStartCharacter(cp[0], false))
+ throw new DatatypeException(0, "invalid Name value");
+ for (int i = 1; i < cp.length; i++)
+ {
+ if (!XMLParser.isNameCharacter(cp[i], false))
+ throw new DatatypeException(i, "invalid Name value");
+ }
+ }
+ catch (IOException e)
+ {
+ DatatypeException e2 = new DatatypeException("invalid Name value");
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/NegativeIntegerType.java b/libjava/classpath/gnu/xml/validation/datatype/NegativeIntegerType.java
new file mode 100644
index 000000000..1e6439c99
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/NegativeIntegerType.java
@@ -0,0 +1,110 @@
+/* NegativeIntegerType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.math.BigInteger;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema negativeInteger type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NegativeIntegerType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.TOTAL_DIGITS,
+ Facet.FRACTION_DIGITS,
+ Facet.PATTERN,
+ Facet.WHITESPACE,
+ Facet.ENUMERATION,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ NegativeIntegerType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "negativeInteger"),
+ TypeLibrary.NON_POSITIVE_INTEGER);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValue(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException(0, "invalid negative integer value");
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == '-')
+ {
+ if (i == 0)
+ continue;
+ }
+ else if (c >= 0x30 && c <= 0x39)
+ continue;
+ throw new DatatypeException(i, "invalid negative integer value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new BigInteger(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/NonNegativeIntegerType.java b/libjava/classpath/gnu/xml/validation/datatype/NonNegativeIntegerType.java
new file mode 100644
index 000000000..c5192f346
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/NonNegativeIntegerType.java
@@ -0,0 +1,120 @@
+/* NonNegativeIntegerType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.math.BigInteger;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema nonNegativeInteger type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NonNegativeIntegerType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.TOTAL_DIGITS,
+ Facet.FRACTION_DIGITS,
+ Facet.PATTERN,
+ Facet.WHITESPACE,
+ Facet.ENUMERATION,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ NonNegativeIntegerType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "nonNegativeInteger"),
+ TypeLibrary.INTEGER);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException(0, "invalid non-negative integer value");
+ boolean negative = false;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == 0x30)
+ continue;
+ else if (c >= 0x31 && c <= 0x39)
+ {
+ if (negative)
+ throw new DatatypeException(i,
+ "invalid non-negative integer value");
+ continue;
+ }
+ else if (c == '+' && i == 0)
+ continue;
+ else if (c == '-' && i == 0)
+ {
+ negative = true;
+ continue;
+ }
+ throw new DatatypeException(i, "invalid non-negative integer value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new BigInteger(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/NonPositiveIntegerType.java b/libjava/classpath/gnu/xml/validation/datatype/NonPositiveIntegerType.java
new file mode 100644
index 000000000..e418c0615
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/NonPositiveIntegerType.java
@@ -0,0 +1,120 @@
+/* NonPositiveIntegerType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.math.BigInteger;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema nonPositiveInteger type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NonPositiveIntegerType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.TOTAL_DIGITS,
+ Facet.FRACTION_DIGITS,
+ Facet.PATTERN,
+ Facet.WHITESPACE,
+ Facet.ENUMERATION,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ NonPositiveIntegerType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "nonPositiveInteger"),
+ TypeLibrary.INTEGER);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException(0, "invalid non-positive integer value");
+ boolean positive = true;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == 0x30)
+ continue;
+ else if (c >= 0x31 && c <= 0x39)
+ {
+ if (positive)
+ throw new DatatypeException(i,
+ "invalid non-positive integer value");
+ continue;
+ }
+ else if (c == '+' && i == 0)
+ continue;
+ else if (c == '-' && i == 0)
+ {
+ positive = false;
+ continue;
+ }
+ throw new DatatypeException(i, "invalid non-positive integer value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new BigInteger(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/NormalizedStringType.java b/libjava/classpath/gnu/xml/validation/datatype/NormalizedStringType.java
new file mode 100644
index 000000000..9009f648a
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/NormalizedStringType.java
@@ -0,0 +1,87 @@
+/* NormalizedStringType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema normalizedString type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NormalizedStringType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ NormalizedStringType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "normalizedString"),
+ TypeLibrary.STRING);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == 0x0a || c == 0x0d || c == 0x09)
+ throw new DatatypeException(i, "invalid normalized-string value");
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/NotationType.java b/libjava/classpath/gnu/xml/validation/datatype/NotationType.java
new file mode 100644
index 000000000..b661cb4e1
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/NotationType.java
@@ -0,0 +1,87 @@
+/* NotationType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema NOTATION type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NotationType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ NotationType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "NOTATION"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ if (!context.isNotation(value))
+ throw new DatatypeException("invalid NOTATION value");
+ }
+
+ public boolean isContextDependent()
+ {
+ return true;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/PatternFacet.java b/libjava/classpath/gnu/xml/validation/datatype/PatternFacet.java
new file mode 100644
index 000000000..9c1cb7e30
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/PatternFacet.java
@@ -0,0 +1,70 @@
+/* PatternFacet.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.regex.Pattern;
+
+/**
+ * The <code>pattern</code> facet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class PatternFacet
+ extends Facet
+{
+
+ public final Pattern value;
+
+ public PatternFacet(Pattern value, Annotation annotation)
+ {
+ super(PATTERN, annotation);
+ this.value = value;
+ }
+
+ public int hashCode()
+ {
+ return value.hashCode();
+ }
+
+ public boolean equals(Object other)
+ {
+ return (other instanceof PatternFacet &&
+ ((PatternFacet) other).value.equals(value));
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/PositiveIntegerType.java b/libjava/classpath/gnu/xml/validation/datatype/PositiveIntegerType.java
new file mode 100644
index 000000000..15d0febfc
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/PositiveIntegerType.java
@@ -0,0 +1,110 @@
+/* PositiveIntegerType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.math.BigInteger;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema positiveInteger type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class PositiveIntegerType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.TOTAL_DIGITS,
+ Facet.FRACTION_DIGITS,
+ Facet.PATTERN,
+ Facet.WHITESPACE,
+ Facet.ENUMERATION,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ PositiveIntegerType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "positiveInteger"),
+ TypeLibrary.NON_NEGATIVE_INTEGER);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException(0, "invalid positive integer value");
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == '+')
+ {
+ if (i == 0)
+ continue;
+ }
+ else if (c >= 0x30 && c <= 0x39)
+ continue;
+ throw new DatatypeException(i, "invalid positive integer value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new BigInteger(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/QNameType.java b/libjava/classpath/gnu/xml/validation/datatype/QNameType.java
new file mode 100644
index 000000000..bdc40c97f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/QNameType.java
@@ -0,0 +1,121 @@
+/* QNameType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.io.IOException;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+import gnu.xml.stream.UnicodeReader;
+import gnu.xml.stream.XMLParser;
+
+/**
+ * The XML Schema QName type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class QNameType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ QNameType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "QName"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int ci = -1;
+ try
+ {
+ int[] cp = UnicodeReader.toCodePointArray(value);
+ if (cp.length == 0)
+ throw new DatatypeException("invalid NCName value");
+ // XXX XML 1.1 documents?
+ if (cp[0] == ':' || !XMLParser.isNameStartCharacter(cp[0], false))
+ throw new DatatypeException(0, "invalid NCName value");
+ for (int i = 1; i < cp.length; i++)
+ {
+ if (cp[i] == ':')
+ {
+ if (ci != -1 || (i + 1 == cp.length))
+ throw new DatatypeException(i, "invalid NCName value");
+ ci = i;
+ }
+ else if (!XMLParser.isNameCharacter(cp[i], false))
+ throw new DatatypeException(i, "invalid NCName value");
+ }
+ }
+ catch (IOException e)
+ {
+ DatatypeException e2 = new DatatypeException("invalid NCName value");
+ e2.initCause(e);
+ throw e2;
+ }
+ if (ci != -1)
+ {
+ String prefix = value.substring(0, ci);
+ if (context.resolveNamespacePrefix(prefix) == null)
+ throw new DatatypeException("invalid namespace prefix");
+ }
+ }
+
+ public boolean isContextDependent()
+ {
+ return true;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/ShortType.java b/libjava/classpath/gnu/xml/validation/datatype/ShortType.java
new file mode 100644
index 000000000..43255571d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/ShortType.java
@@ -0,0 +1,132 @@
+/* ShortType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema short type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class ShortType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.TOTAL_DIGITS,
+ Facet.FRACTION_DIGITS,
+ Facet.PATTERN,
+ Facet.WHITESPACE,
+ Facet.ENUMERATION,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ static final String MAX_VALUE = "32767";
+ static final String MIN_VALUE = "32768";
+ static final int LENGTH = MAX_VALUE.length();
+
+ ShortType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "short"),
+ TypeLibrary.INT);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException(0, "invalid short value");
+ int i = 0, off = 0;
+ boolean compare = false;
+ String compareTo = MAX_VALUE;
+ char c = value.charAt(0);
+ if (c == '+')
+ i++;
+ else if (c == '-')
+ {
+ compareTo = MIN_VALUE;
+ i++;
+ }
+ if (len - i > LENGTH)
+ throw new DatatypeException(i, "invalid short value");
+ else if (len - i == LENGTH)
+ compare = true;
+ for (; i < len; i++)
+ {
+ c = value.charAt(i);
+ if (c >= 0x30 && c <= 0x39)
+ {
+ if (compare)
+ {
+ char d = compareTo.charAt(off);
+ if (Character.digit(c, 10) > Character.digit(d, 10))
+ throw new DatatypeException(i, "invalid short value");
+ }
+ off++;
+ continue;
+ }
+ throw new DatatypeException(i, "invalid short value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new Short(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/SimpleType.java b/libjava/classpath/gnu/xml/validation/datatype/SimpleType.java
new file mode 100644
index 000000000..1233723bd
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/SimpleType.java
@@ -0,0 +1,255 @@
+/* SimpleType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.Iterator;
+import java.util.Set;
+import java.util.regex.Matcher;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.Datatype;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.DatatypeStreamingValidator;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * An XML Schema simple type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class SimpleType
+ extends Type
+ implements Datatype
+{
+
+ /**
+ * The variety of the <code>anySimpleType</code> datatype.
+ */
+ public static final int ANY = 0;
+
+ /**
+ * The atomic variety.
+ */
+ public static final int ATOMIC = 1;
+
+ /**
+ * The list variety.
+ */
+ public static final int LIST = 2;
+
+ /**
+ * The union variety.
+ */
+ public static final int UNION = 3;
+
+ public static final int ID_TYPE_NULL = 0;
+ public static final int ID_TYPE_ID = 1;
+ public static final int ID_TYPE_IDREF = 2;
+ public static final int ID_TYPE_IDREFS = 3;
+
+ /**
+ * The variety of this simple type.
+ */
+ public final int variety;
+
+ /**
+ * The facets of this simple type.
+ */
+ public Set facets;
+
+ /**
+ * The fundamental facets of this simple type.
+ */
+ public int fundamentalFacets;
+
+ /**
+ * If this datatype has been derived by restriction, then the component
+ * from which it was derived.
+ */
+ public final SimpleType baseType;
+
+ /**
+ * Optional annotation.
+ */
+ public final Annotation annotation;
+
+ public SimpleType(QName name, int variety, Set facets,
+ int fundamentalFacets, SimpleType baseType,
+ Annotation annotation)
+ {
+ super(name);
+ this.variety = variety;
+ this.facets = facets;
+ this.fundamentalFacets = fundamentalFacets;
+ this.baseType = baseType;
+ this.annotation = annotation;
+ }
+
+ /**
+ * Indicates whether this type permits the specified value.
+ */
+ public boolean isValid(String value, ValidationContext context)
+ {
+ try
+ {
+ checkValid(value, context);
+ return true;
+ }
+ catch (DatatypeException e)
+ {
+ return false;
+ }
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ if (facets != null && !facets.isEmpty())
+ {
+ Object parsedValue = createValue(value, context);
+ for (Iterator i = facets.iterator(); i.hasNext(); )
+ {
+ Facet facet = (Facet) i.next();
+ switch (facet.type)
+ {
+ case Facet.LENGTH:
+ LengthFacet lf = (LengthFacet) facet;
+ if (value.length() != lf.value)
+ throw new DatatypeException("invalid length");
+ break;
+ case Facet.MIN_LENGTH:
+ MinLengthFacet nlf = (MinLengthFacet) facet;
+ if (value.length() < nlf.value)
+ throw new DatatypeException("invalid minimum length");
+ break;
+ case Facet.MAX_LENGTH:
+ MaxLengthFacet xlf = (MaxLengthFacet) facet;
+ if (value.length() > xlf.value)
+ throw new DatatypeException("invalid maximum length");
+ break;
+ case Facet.PATTERN:
+ PatternFacet pf = (PatternFacet) facet;
+ Matcher matcher = pf.value.matcher(value);
+ if (!matcher.find())
+ throw new DatatypeException("invalid match for pattern");
+ break;
+ case Facet.ENUMERATION:
+ // TODO
+ break;
+ case Facet.WHITESPACE:
+ // TODO
+ break;
+ case Facet.MAX_INCLUSIVE:
+ MaxInclusiveFacet xif = (MaxInclusiveFacet) facet;
+ if (!xif.matches(parsedValue))
+ throw new DatatypeException("beyond upper bound");
+ break;
+ case Facet.MAX_EXCLUSIVE:
+ MaxExclusiveFacet xef = (MaxExclusiveFacet) facet;
+ if (!xef.matches(parsedValue))
+ throw new DatatypeException("beyond upper bound");
+ break;
+ case Facet.MIN_EXCLUSIVE:
+ MinExclusiveFacet nef = (MinExclusiveFacet) facet;
+ if (!nef.matches(parsedValue))
+ throw new DatatypeException("beyond lower bound");
+ break;
+ case Facet.MIN_INCLUSIVE:
+ MinInclusiveFacet nif = (MinInclusiveFacet) facet;
+ if (!nif.matches(parsedValue))
+ throw new DatatypeException("beyond lower bound");
+ break;
+ case Facet.TOTAL_DIGITS:
+ TotalDigitsFacet tdf = (TotalDigitsFacet) facet;
+ if (countDigits(value, true) > tdf.value)
+ throw new DatatypeException("too many digits");
+ break;
+ case Facet.FRACTION_DIGITS:
+ FractionDigitsFacet fdf = (FractionDigitsFacet) facet;
+ if (countDigits(value, false) > fdf.value)
+ throw new DatatypeException("too many fraction digits");
+ break;
+ }
+ }
+ }
+ }
+
+ private static int countDigits(String value, boolean any)
+ {
+ int count = 0;
+ int len = value.length();
+ boolean seenDecimal = false;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == 0x2e)
+ seenDecimal = true;
+ else if (c >= 0x30 && c <= 0x39 && (any || seenDecimal))
+ count++;
+ }
+ return count;
+ }
+
+ // TODO createStreamingValidator
+ public DatatypeStreamingValidator createStreamingValidator(ValidationContext context)
+ {
+ throw new UnsupportedOperationException();
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ return literal;
+ }
+
+ public boolean sameValue(Object value1, Object value2) {
+ return value1.equals(value2);
+ }
+
+ public int valueHashCode(Object value) {
+ return value.hashCode();
+ }
+
+ public int getIdType()
+ {
+ return ID_TYPE_NULL;
+ }
+
+ public boolean isContextDependent()
+ {
+ return false;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/StringType.java b/libjava/classpath/gnu/xml/validation/datatype/StringType.java
new file mode 100644
index 000000000..e20d1b87e
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/StringType.java
@@ -0,0 +1,72 @@
+/* StringType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+
+/**
+ * The XML Schema string type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class StringType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ StringType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "string"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/TimeType.java b/libjava/classpath/gnu/xml/validation/datatype/TimeType.java
new file mode 100644
index 000000000..83ada5bc6
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/TimeType.java
@@ -0,0 +1,302 @@
+/* TimeType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.TimeZone;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema time type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class TimeType
+ extends AtomicSimpleType
+{
+
+ static class Time
+ implements Comparable
+ {
+ int minutes;
+ float seconds;
+
+ public int hashCode()
+ {
+ return minutes * 31 + new Float(seconds).hashCode();
+ }
+
+ public boolean equals(Object other)
+ {
+ if (other instanceof Time)
+ {
+ Time time = (Time) other;
+ return time.minutes == minutes && time.seconds == seconds;
+ }
+ return false;
+ }
+
+ public int compareTo(Object other)
+ {
+ if (other instanceof Time)
+ {
+ Time time = (Time) other;
+ if (time.minutes != minutes)
+ return minutes - time.minutes;
+ if (time.seconds == seconds)
+ return 0;
+ return (seconds < time.seconds) ? -1 : 1;
+ }
+ return 0;
+ }
+
+ }
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ TimeType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "time"),
+ TypeLibrary.ANY_SIMPLE_TYPE);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ int state = 3;
+ int start = 0;
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == '-' && state == 0)
+ {
+ start++;
+ continue;
+ }
+ if (c >= 0x30 && c <= 0x39)
+ continue;
+ switch (state)
+ {
+ case 3: // hour
+ if (c == ':')
+ {
+ if (i - start != 2)
+ throw new DatatypeException(i, "invalid time value");
+ state = 4;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 4: // minute
+ if (c == ':')
+ {
+ if (i - start != 2)
+ throw new DatatypeException(i, "invalid time value");
+ state = 5;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 5: // second
+ if (c == '.')
+ {
+ if (i - start != 2)
+ throw new DatatypeException(i, "invalid time value");
+ state = 6;
+ start = i + 1;
+ continue;
+ }
+ else if (c == ' ')
+ {
+ if (i - start != 2)
+ throw new DatatypeException(i, "invalid time value");
+ state = 7;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 6: // second fraction
+ if (c == ' ')
+ {
+ state = 7;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 7: // timezone 1
+ if (start == i)
+ {
+ if (c == '+' || c == '-')
+ continue;
+ else if (c == 'Z')
+ {
+ state = 9;
+ start = i + 1;
+ continue;
+ }
+ }
+ if (c == ':')
+ {
+ if (i - start != 2)
+ throw new DatatypeException(i, "invalid time value");
+ state = 8;
+ start = i + 1;
+ continue;
+ }
+ break;
+ }
+ throw new DatatypeException(i, "invalid time value");
+ }
+ switch (state)
+ {
+ case 5: // second
+ if (len - start != 2)
+ throw new DatatypeException(len, "invalid time value");
+ break;
+ case 6: // second fraction
+ break;
+ case 8: // timezone 2
+ if (len - start != 2)
+ throw new DatatypeException(len, "invalid time value");
+ break;
+ case 9: // post Z
+ break;
+ default:
+ throw new DatatypeException(len, "invalid time value");
+ }
+ }
+
+ public Object createValue(String value, ValidationContext context) {
+ int len = value.length();
+ int state = 3;
+ int start = 0;
+ Time time = new Time();
+ try
+ {
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c >= 0x30 && c <= 0x39)
+ continue;
+ switch (state)
+ {
+ case 3: // hour
+ if (c == ':')
+ {
+ time.minutes =
+ Integer.parseInt(value.substring(start, i)) * 60;
+ state = 4;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 4: // minute
+ if (c == ':')
+ {
+ time.minutes +=
+ Integer.parseInt(value.substring(start, i));
+ state = 5;
+ start = i + 1;
+ continue;
+ }
+ break;
+ case 5: // second
+ if (c == ' ')
+ {
+ time.seconds =
+ Float.parseFloat(value.substring(start, i));
+ state = 7;
+ start = i + 1;
+ continue;
+ }
+ break;
+ }
+ }
+ // end of input
+ if (len - start > 0 && state == 7)
+ {
+ // Timezone
+ String timezone = value.substring(len - start);
+ int i = timezone.indexOf(':');
+ if (i == -1)
+ {
+ if ("Z".equals(timezone))
+ timezone = "UTC";
+ TimeZone tz = TimeZone.getTimeZone(timezone);
+ if (tz == null)
+ return null;
+ time.minutes += tz.getRawOffset();
+ }
+ else
+ {
+ String tzh = timezone.substring(0, i);
+ String tzm = timezone.substring(i + 1);
+ int offset = Integer.parseInt(tzh) * 60;
+ if (offset < 0)
+ offset -= Integer.parseInt(tzm);
+ else
+ offset += Integer.parseInt(tzm);
+ time.minutes += offset;
+ }
+ }
+ return time;
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/TokenType.java b/libjava/classpath/gnu/xml/validation/datatype/TokenType.java
new file mode 100644
index 000000000..dfe5f14ce
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/TokenType.java
@@ -0,0 +1,95 @@
+/* TokenType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema token type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class TokenType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.LENGTH,
+ Facet.MIN_LENGTH,
+ Facet.MAX_LENGTH,
+ Facet.PATTERN,
+ Facet.ENUMERATION,
+ Facet.WHITESPACE
+ };
+
+ TokenType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "token"),
+ TypeLibrary.NORMALIZED_STRING);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException(0, "invalid token value");
+ if (value.charAt(0) == ' ' || value.charAt(len - 1) == ' ')
+ throw new DatatypeException(0, "invalid token value");
+ char last = '\u0000';
+ for (int i = 0; i < len; i++)
+ {
+ char c = value.charAt(i);
+ if (c == 0x0a || c == 0x0d || c == 0x09)
+ throw new DatatypeException(i, "invalid token value");
+ if (c == ' ' && last == ' ')
+ throw new DatatypeException(i, "invalid token value");
+ last = c;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/TotalDigitsFacet.java b/libjava/classpath/gnu/xml/validation/datatype/TotalDigitsFacet.java
new file mode 100644
index 000000000..25b50cd6f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/TotalDigitsFacet.java
@@ -0,0 +1,71 @@
+/* TotalDigitsFacet.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+/**
+ * The <code>totalDigits</code> facet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class TotalDigitsFacet
+ extends Facet
+{
+
+ public final int value;
+
+ public final boolean fixed;
+
+ public TotalDigitsFacet(int value, boolean fixed, Annotation annotation)
+ {
+ super(TOTAL_DIGITS, annotation);
+ this.value = value;
+ this.fixed = fixed;
+ }
+
+ public int hashCode()
+ {
+ return value;
+ }
+
+ public boolean equals(Object other)
+ {
+ return (other instanceof TotalDigitsFacet &&
+ ((TotalDigitsFacet) other).value == value);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/Type.java b/libjava/classpath/gnu/xml/validation/datatype/Type.java
new file mode 100644
index 000000000..ebd650933
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/Type.java
@@ -0,0 +1,62 @@
+/* Type.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.namespace.QName;
+/**
+ * Abstract base class for XML Schema datatypes.
+ * @see http://www.w3.org/TR/xmlschema-2/
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public abstract class Type
+{
+
+ public static final Type ANY_TYPE = new AnyType();
+
+ /**
+ * The name of this type.
+ */
+ public final QName name;
+
+ public Type(QName name)
+ {
+ this.name = name;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/TypeBuilder.java b/libjava/classpath/gnu/xml/validation/datatype/TypeBuilder.java
new file mode 100644
index 000000000..087333153
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/TypeBuilder.java
@@ -0,0 +1,278 @@
+/* TypeBuilder.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.LinkedHashSet;
+import java.util.regex.Pattern;
+import org.relaxng.datatype.Datatype;
+import org.relaxng.datatype.DatatypeBuilder;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * Datatype builder.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class TypeBuilder
+ implements DatatypeBuilder
+{
+
+ final SimpleType type;
+
+ TypeBuilder(SimpleType type)
+ {
+ this.type = type;
+ // TODO fundamental facets
+ type.facets = new LinkedHashSet();
+ }
+
+ public void addParameter(String name, String value, ValidationContext context)
+ throws DatatypeException
+ {
+ // TODO fundamental facets
+ if ("length".equals(name))
+ type.facets.add(parseLengthFacet(value));
+ else if ("minLength".equals(name))
+ type.facets.add(parseMinLengthFacet(value));
+ else if ("maxLength".equals(name))
+ type.facets.add(parseMaxLengthFacet(value));
+ else if ("pattern".equals(name))
+ type.facets.add(parsePatternFacet(value));
+ else if ("enumeration".equals(name))
+ type.facets.add(parseEnumerationFacet(value));
+ else if ("whiteSpace".equals(name))
+ type.facets.add(parseWhiteSpaceFacet(value));
+ else if ("maxInclusive".equals(name))
+ type.facets.add(parseMaxInclusiveFacet(value, context));
+ else if ("maxExclusive".equals(name))
+ type.facets.add(parseMaxExclusiveFacet(value, context));
+ else if ("minExclusive".equals(name))
+ type.facets.add(parseMinExclusiveFacet(value, context));
+ else if ("minInclusive".equals(name))
+ type.facets.add(parseMinInclusiveFacet(value, context));
+ else if ("totalDigits".equals(name))
+ type.facets.add(parseTotalDigitsFacet(value));
+ else if ("fractionDigits".equals(name))
+ type.facets.add(parseFractionDigitsFacet(value));
+ }
+
+ LengthFacet parseLengthFacet(String value)
+ throws DatatypeException
+ {
+ int si = value.indexOf(' ');
+ boolean fixed = false;
+ if (si != -1)
+ {
+ if (!"FIXED".equalsIgnoreCase(value.substring(si + 1)))
+ throw new DatatypeException("second argument must be FIXED if present");
+ fixed = true;
+ value = value.substring(0, si);
+ }
+ return new LengthFacet(Integer.parseInt(value), fixed, null);
+ }
+
+ MinLengthFacet parseMinLengthFacet(String value)
+ throws DatatypeException
+ {
+ int si = value.indexOf(' ');
+ boolean fixed = false;
+ if (si != -1)
+ {
+ if (!"FIXED".equalsIgnoreCase(value.substring(si + 1)))
+ throw new DatatypeException("second argument must be FIXED if present");
+ fixed = true;
+ value = value.substring(0, si);
+ }
+ return new MinLengthFacet(Integer.parseInt(value), fixed, null);
+ }
+
+ MaxLengthFacet parseMaxLengthFacet(String value)
+ throws DatatypeException
+ {
+ int si = value.indexOf(' ');
+ boolean fixed = false;
+ if (si != -1)
+ {
+ if (!"FIXED".equalsIgnoreCase(value.substring(si + 1)))
+ throw new DatatypeException("second argument must be FIXED if present");
+ fixed = true;
+ value = value.substring(0, si);
+ }
+ return new MaxLengthFacet(Integer.parseInt(value), fixed, null);
+ }
+
+ PatternFacet parsePatternFacet(String value)
+ throws DatatypeException
+ {
+ return new PatternFacet(Pattern.compile(value), null);
+ }
+
+ EnumerationFacet parseEnumerationFacet(String value)
+ throws DatatypeException
+ {
+ return new EnumerationFacet(value, null);
+ }
+
+ WhiteSpaceFacet parseWhiteSpaceFacet(String value)
+ throws DatatypeException
+ {
+ int si = value.indexOf(' ');
+ boolean fixed = false;
+ if (si != -1)
+ {
+ if (!"FIXED".equalsIgnoreCase(value.substring(si + 1)))
+ throw new DatatypeException("second argument must be FIXED if present");
+ fixed = true;
+ value = value.substring(0, si);
+ }
+ if ("preserve".equals(value))
+ return new WhiteSpaceFacet(WhiteSpaceFacet.PRESERVE, fixed, null);
+ if ("replace".equals(value))
+ return new WhiteSpaceFacet(WhiteSpaceFacet.REPLACE, fixed, null);
+ if ("collapse".equals(value))
+ return new WhiteSpaceFacet(WhiteSpaceFacet.COLLAPSE, fixed, null);
+ throw new DatatypeException("argument must be preserve, replace, or collapse");
+ }
+
+ MaxInclusiveFacet parseMaxInclusiveFacet(String value,
+ ValidationContext context)
+ throws DatatypeException
+ {
+ int si = value.indexOf(' ');
+ boolean fixed = false;
+ if (si != -1)
+ {
+ if (!"FIXED".equalsIgnoreCase(value.substring(si + 1)))
+ throw new DatatypeException("second argument must be FIXED if present");
+ fixed = true;
+ value = value.substring(0, si);
+ }
+ return new MaxInclusiveFacet(type.createValue(value, context), fixed, null);
+ }
+
+ MaxExclusiveFacet parseMaxExclusiveFacet(String value,
+ ValidationContext context)
+ throws DatatypeException
+ {
+ int si = value.indexOf(' ');
+ boolean fixed = false;
+ if (si != -1)
+ {
+ if (!"FIXED".equalsIgnoreCase(value.substring(si + 1)))
+ throw new DatatypeException("second argument must be FIXED if present");
+ fixed = true;
+ value = value.substring(0, si);
+ }
+ return new MaxExclusiveFacet(type.createValue(value, context), fixed, null);
+ }
+
+ MinExclusiveFacet parseMinExclusiveFacet(String value,
+ ValidationContext context)
+ throws DatatypeException
+ {
+ int si = value.indexOf(' ');
+ boolean fixed = false;
+ if (si != -1)
+ {
+ if (!"FIXED".equalsIgnoreCase(value.substring(si + 1)))
+ throw new DatatypeException("second argument must be FIXED if present");
+ fixed = true;
+ value = value.substring(0, si);
+ }
+ return new MinExclusiveFacet(type.createValue(value, context), fixed, null);
+ }
+
+ MinInclusiveFacet parseMinInclusiveFacet(String value,
+ ValidationContext context)
+ throws DatatypeException
+ {
+ int si = value.indexOf(' ');
+ boolean fixed = false;
+ if (si != -1)
+ {
+ if (!"FIXED".equalsIgnoreCase(value.substring(si + 1)))
+ throw new DatatypeException("second argument must be FIXED if present");
+ fixed = true;
+ value = value.substring(0, si);
+ }
+ return new MinInclusiveFacet(type.createValue(value, context), fixed, null);
+ }
+
+ TotalDigitsFacet parseTotalDigitsFacet(String value)
+ throws DatatypeException
+ {
+ int si = value.indexOf(' ');
+ boolean fixed = false;
+ if (si != -1)
+ {
+ if (!"FIXED".equalsIgnoreCase(value.substring(si + 1)))
+ throw new DatatypeException("second argument must be FIXED if present");
+ fixed = true;
+ value = value.substring(0, si);
+ }
+ int val = Integer.parseInt(value);
+ if (val < 0)
+ throw new DatatypeException("value must be a positiveInteger");
+ return new TotalDigitsFacet(val, fixed, null);
+ }
+
+ FractionDigitsFacet parseFractionDigitsFacet(String value)
+ throws DatatypeException
+ {
+ int si = value.indexOf(' ');
+ boolean fixed = false;
+ if (si != -1)
+ {
+ if (!"FIXED".equalsIgnoreCase(value.substring(si + 1)))
+ throw new DatatypeException("second argument must be FIXED if present");
+ fixed = true;
+ value = value.substring(0, si);
+ }
+ int val = Integer.parseInt(value);
+ if (val < 0)
+ throw new DatatypeException("value must be a positiveInteger");
+ return new FractionDigitsFacet(val, fixed, null);
+ }
+
+ public Datatype createDatatype()
+ {
+ return type;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/TypeLibrary.java b/libjava/classpath/gnu/xml/validation/datatype/TypeLibrary.java
new file mode 100644
index 000000000..4db48f799
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/TypeLibrary.java
@@ -0,0 +1,173 @@
+/* TypeLibrary.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.relaxng.datatype.Datatype;
+import org.relaxng.datatype.DatatypeBuilder;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.DatatypeLibrary;
+
+/**
+ * Datatype library for XML Schema datatypes.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class TypeLibrary
+ implements DatatypeLibrary
+{
+
+ public static final SimpleType ANY_SIMPLE_TYPE = new AnySimpleType();
+
+ public static final SimpleType STRING = new StringType();
+ public static final SimpleType BOOLEAN = new BooleanType();
+ public static final SimpleType DECIMAL = new DecimalType();
+ public static final SimpleType FLOAT = new FloatType();
+ public static final SimpleType DOUBLE = new DoubleType();
+ public static final SimpleType DURATION = new DurationType();
+ public static final SimpleType DATE_TIME = new DateTimeType();
+ public static final SimpleType TIME = new TimeType();
+ public static final SimpleType DATE = new DateType();
+ public static final SimpleType G_YEAR_MONTH = new GYearMonthType();
+ public static final SimpleType G_YEAR = new GYearType();
+ public static final SimpleType G_MONTH_DAY = new GMonthDayType();
+ public static final SimpleType G_DAY = new GDayType();
+ public static final SimpleType G_MONTH = new GMonthType();
+ public static final SimpleType HEX_BINARY = new HexBinaryType();
+ public static final SimpleType BASE64_BINARY = new Base64BinaryType();
+ public static final SimpleType ANY_URI = new AnyURIType();
+ public static final SimpleType QNAME = new QNameType();
+ public static final SimpleType NOTATION = new NotationType();
+
+ public static final SimpleType NORMALIZED_STRING = new NormalizedStringType();
+ public static final SimpleType TOKEN = new TokenType();
+ public static final SimpleType LANGUAGE = new LanguageType();
+ public static final SimpleType NMTOKEN = new NMTokenType();
+ public static final SimpleType NMTOKENS = new NMTokensType();
+ public static final SimpleType NAME = new NameType();
+ public static final SimpleType NCNAME = new NCNameType();
+ public static final SimpleType ID = new IDType();
+ public static final SimpleType IDREF = new IDRefType();
+ public static final SimpleType IDREFS = new IDRefsType();
+ public static final SimpleType ENTITY = new EntityType();
+ public static final SimpleType ENTITIES = new EntitiesType();
+ public static final SimpleType INTEGER = new IntegerType();
+ public static final SimpleType NON_POSITIVE_INTEGER = new NonPositiveIntegerType();
+ public static final SimpleType NEGATIVE_INTEGER = new NegativeIntegerType();
+ public static final SimpleType LONG = new LongType();
+ public static final SimpleType INT = new IntType();
+ public static final SimpleType SHORT = new ShortType();
+ public static final SimpleType BYTE = new ByteType();
+ public static final SimpleType NON_NEGATIVE_INTEGER = new NonNegativeIntegerType();
+ public static final SimpleType UNSIGNED_LONG = new UnsignedLongType();
+ public static final SimpleType UNSIGNED_INT = new UnsignedIntType();
+ public static final SimpleType UNSIGNED_SHORT = new UnsignedShortType();
+ public static final SimpleType UNSIGNED_BYTE = new UnsignedByteType();
+ public static final SimpleType POSITIVE_INTEGER = new PositiveIntegerType();
+
+ private static Map byName;
+ static
+ {
+ byName = new HashMap();
+ byName.put("anySimpleType", ANY_SIMPLE_TYPE);
+ byName.put("string", STRING);
+ byName.put("boolean", BOOLEAN);
+ byName.put("decimal", DECIMAL);
+ byName.put("float", FLOAT);
+ byName.put("double", DOUBLE);
+ byName.put("duration", DURATION);
+ byName.put("dateTime", DATE_TIME);
+ byName.put("time", TIME);
+ byName.put("date", DATE);
+ byName.put("gYearMonth", G_YEAR_MONTH);
+ byName.put("gYear", G_YEAR);
+ byName.put("gMonthDay", G_MONTH_DAY);
+ byName.put("gDay", G_DAY);
+ byName.put("gMonth",G_MONTH);
+ byName.put("hexBinary", HEX_BINARY);
+ byName.put("base64Binary", BASE64_BINARY);
+ byName.put("anyURI", ANY_URI);
+ byName.put("QName", QNAME);
+ byName.put("NOTATION", NOTATION);
+ byName.put("normalizedString", NORMALIZED_STRING);
+ byName.put("token", TOKEN);
+ byName.put("language", LANGUAGE);
+ byName.put("NMTOKEN", NMTOKEN);
+ byName.put("NMTOKENS", NMTOKENS);
+ byName.put("Name", NAME);
+ byName.put("NCName", NCNAME);
+ byName.put("ID", ID);
+ byName.put("IDREF", IDREF);
+ byName.put("IDREFS", IDREFS);
+ byName.put("ENTITY", ENTITY);
+ byName.put("ENTITIES", ENTITIES);
+ byName.put("integer", INTEGER);
+ byName.put("nonPositiveInteger", NON_POSITIVE_INTEGER);
+ byName.put("negativeInteger", NEGATIVE_INTEGER);
+ byName.put("long", LONG);
+ byName.put("int", INT);
+ byName.put("short", SHORT);
+ byName.put("byte", BYTE);
+ byName.put("nonNegativeInteger", NON_NEGATIVE_INTEGER);
+ byName.put("unsignedLong", UNSIGNED_LONG);
+ byName.put("unsignedInt", UNSIGNED_INT);
+ byName.put("unsignedShort", UNSIGNED_SHORT);
+ byName.put("unsignedByte", UNSIGNED_BYTE);
+ byName.put("positiveInteger", POSITIVE_INTEGER);
+ }
+
+ public DatatypeBuilder createDatatypeBuilder(String baseTypeLocalName)
+ throws DatatypeException
+ {
+ SimpleType type = (SimpleType) byName.get(baseTypeLocalName);
+ if (type == null)
+ throw new DatatypeException("Unknown type name: " + baseTypeLocalName);
+ return new TypeBuilder(type);
+ }
+
+ public Datatype createDatatype(String typeLocalName)
+ throws DatatypeException
+ {
+ SimpleType type = (SimpleType) byName.get(typeLocalName);
+ if (type == null)
+ throw new DatatypeException("Unknown type name: " + typeLocalName);
+ return type;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/TypeLibraryFactory.java b/libjava/classpath/gnu/xml/validation/datatype/TypeLibraryFactory.java
new file mode 100644
index 000000000..2f9bbd3c6
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/TypeLibraryFactory.java
@@ -0,0 +1,60 @@
+/* TypeLibraryFactory.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import org.relaxng.datatype.DatatypeLibrary;
+import org.relaxng.datatype.DatatypeLibraryFactory;
+
+/**
+ * Datatype library factory for XML Schema datatypes.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class TypeLibraryFactory
+ implements DatatypeLibraryFactory
+{
+
+ public DatatypeLibrary createDatatypeLibrary(String namespaceURI)
+ {
+ if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(namespaceURI))
+ return new TypeLibrary();
+ return null;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/UnionSimpleType.java b/libjava/classpath/gnu/xml/validation/datatype/UnionSimpleType.java
new file mode 100644
index 000000000..253e1df7b
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/UnionSimpleType.java
@@ -0,0 +1,82 @@
+/* UnionSimpleType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * An XML Schema union simple type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class UnionSimpleType
+ extends SimpleType
+{
+
+ /**
+ * The member types in this union.
+ */
+ public final List memberTypes;
+
+ public UnionSimpleType(QName name, Set facets,
+ int fundamentalFacets, SimpleType baseType,
+ Annotation annotation, List memberTypes)
+ {
+ super(name, UNION, facets, fundamentalFacets, baseType, annotation);
+ this.memberTypes = memberTypes;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ for (Iterator i = memberTypes.iterator(); i.hasNext(); )
+ {
+ SimpleType type = (SimpleType) i.next();
+ if (type.isValid(value, context))
+ return;
+ }
+ throw new DatatypeException("invalid union type value");
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/UnsignedByteType.java b/libjava/classpath/gnu/xml/validation/datatype/UnsignedByteType.java
new file mode 100644
index 000000000..cf12abe3a
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/UnsignedByteType.java
@@ -0,0 +1,120 @@
+/* UnsignedByteType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema unsignedByte type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class UnsignedByteType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.TOTAL_DIGITS,
+ Facet.FRACTION_DIGITS,
+ Facet.PATTERN,
+ Facet.WHITESPACE,
+ Facet.ENUMERATION,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ static final String MAX_VALUE = "255";
+ static final int LENGTH = MAX_VALUE.length();
+
+ UnsignedByteType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "unsignedByte"),
+ TypeLibrary.UNSIGNED_SHORT);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException(0, "invalid unsigned byte value");
+ boolean compare = false;
+ for (int i = 0; i < len; i++)
+ {
+ if (len - i > LENGTH)
+ throw new DatatypeException(i, "invalid unsigned byte value");
+ else if (len - i == LENGTH)
+ compare = true;
+ char c = value.charAt(i);
+ if (c >= 0x30 && c <= 0x39)
+ {
+ if (compare)
+ {
+ char d = MAX_VALUE.charAt(i);
+ if (Character.digit(c, 10) > Character.digit(d, 10))
+ throw new DatatypeException(i, "invalid unsigned byte value");
+ }
+ continue;
+ }
+ throw new DatatypeException(i, "invalid unsigned byte value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new Byte(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/UnsignedIntType.java b/libjava/classpath/gnu/xml/validation/datatype/UnsignedIntType.java
new file mode 100644
index 000000000..b634442bb
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/UnsignedIntType.java
@@ -0,0 +1,120 @@
+/* UnsignedIntType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema unsignedInt type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class UnsignedIntType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.TOTAL_DIGITS,
+ Facet.FRACTION_DIGITS,
+ Facet.PATTERN,
+ Facet.WHITESPACE,
+ Facet.ENUMERATION,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ static final String MAX_VALUE = "4294967295";
+ static final int LENGTH = MAX_VALUE.length();
+
+ UnsignedIntType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "unsignedInt"),
+ TypeLibrary.UNSIGNED_LONG);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException(0, "invalid unsigned int value");
+ boolean compare = false;
+ for (int i = 0; i < len; i++)
+ {
+ if (len - i > LENGTH)
+ throw new DatatypeException(i, "invalid unsigned int value");
+ else if (len - i == LENGTH)
+ compare = true;
+ char c = value.charAt(i);
+ if (c >= 0x30 && c <= 0x39)
+ {
+ if (compare)
+ {
+ char d = MAX_VALUE.charAt(i);
+ if (Character.digit(c, 10) > Character.digit(d, 10))
+ throw new DatatypeException(i, "invalid unsigned int value");
+ }
+ continue;
+ }
+ throw new DatatypeException(i, "invalid unsigned int value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new Integer(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/UnsignedLongType.java b/libjava/classpath/gnu/xml/validation/datatype/UnsignedLongType.java
new file mode 100644
index 000000000..784b86663
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/UnsignedLongType.java
@@ -0,0 +1,120 @@
+/* UnsignedLongType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema unsignedLong type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class UnsignedLongType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.TOTAL_DIGITS,
+ Facet.FRACTION_DIGITS,
+ Facet.PATTERN,
+ Facet.WHITESPACE,
+ Facet.ENUMERATION,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ static final String MAX_VALUE = "18446744073709551615";
+ static final int LENGTH = MAX_VALUE.length();
+
+ UnsignedLongType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "unsignedLong"),
+ TypeLibrary.NON_NEGATIVE_INTEGER);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException(0, "invalid unsigned long value");
+ boolean compare = false;
+ for (int i = 0; i < len; i++)
+ {
+ if (len - i > LENGTH)
+ throw new DatatypeException(i, "invalid unsigned long value");
+ else if (len - i == LENGTH)
+ compare = true;
+ char c = value.charAt(i);
+ if (c >= 0x30 && c <= 0x39)
+ {
+ if (compare)
+ {
+ char d = MAX_VALUE.charAt(i);
+ if (Character.digit(c, 10) > Character.digit(d, 10))
+ throw new DatatypeException(i, "invalid unsigned long value");
+ }
+ continue;
+ }
+ throw new DatatypeException(i, "invalid unsigned long value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new Long(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/UnsignedShortType.java b/libjava/classpath/gnu/xml/validation/datatype/UnsignedShortType.java
new file mode 100644
index 000000000..ececb608c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/UnsignedShortType.java
@@ -0,0 +1,121 @@
+/* UnsignedShortType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.ValidationContext;
+
+/**
+ * The XML Schema unsignedShort type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class UnsignedShortType
+ extends AtomicSimpleType
+{
+
+ static final int[] CONSTRAINING_FACETS = {
+ Facet.TOTAL_DIGITS,
+ Facet.FRACTION_DIGITS,
+ Facet.PATTERN,
+ Facet.WHITESPACE,
+ Facet.ENUMERATION,
+ Facet.MAX_INCLUSIVE,
+ Facet.MAX_EXCLUSIVE,
+ Facet.MIN_INCLUSIVE,
+ Facet.MIN_EXCLUSIVE
+ };
+
+ static final String MAX_VALUE = "65535";
+ static final int LENGTH = MAX_VALUE.length();
+
+ UnsignedShortType()
+ {
+ super(new QName(XMLConstants.W3C_XML_SCHEMA_NS_URI, "unsignedShort"),
+ TypeLibrary.UNSIGNED_INT);
+ }
+
+ public int[] getConstrainingFacets()
+ {
+ return CONSTRAINING_FACETS;
+ }
+
+ public void checkValid(String value, ValidationContext context)
+ throws DatatypeException
+ {
+ super.checkValid(value, context);
+ int len = value.length();
+ if (len == 0)
+ throw new DatatypeException(0, "invalid unsigned short value");
+ boolean compare = false;
+ for (int i = 0; i < len; i++)
+ {
+ if (len - i > LENGTH)
+ throw new DatatypeException(i, "invalid unsigned short value");
+ else if (len - i == LENGTH)
+ compare = true;
+ char c = value.charAt(i);
+ if (c >= 0x30 && c <= 0x39)
+ {
+ if (compare)
+ {
+ char d = MAX_VALUE.charAt(i);
+ if (Character.digit(c, 10) > Character.digit(d, 10))
+ throw new DatatypeException(i,
+ "invalid unsigned short value");
+ }
+ continue;
+ }
+ throw new DatatypeException(i, "invalid unsigned short value");
+ }
+ }
+
+ public Object createValue(String literal, ValidationContext context) {
+ try
+ {
+ return new Short(literal);
+ }
+ catch (NumberFormatException e)
+ {
+ return null;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/datatype/WhiteSpaceFacet.java b/libjava/classpath/gnu/xml/validation/datatype/WhiteSpaceFacet.java
new file mode 100644
index 000000000..0f2109cfc
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/datatype/WhiteSpaceFacet.java
@@ -0,0 +1,74 @@
+/* WhiteSpaceFacet.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.datatype;
+
+/**
+ * The <code>whiteSpace</code> facet.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class WhiteSpaceFacet
+ extends Facet
+{
+
+ public static final int PRESERVE = 0;
+ public static final int REPLACE = 1;
+ public static final int COLLAPSE = 2;
+
+ public final int value;
+ public final boolean fixed;
+
+ public WhiteSpaceFacet(int value, boolean fixed, Annotation annotation)
+ {
+ super(WHITESPACE, annotation);
+ this.value = value;
+ this.fixed = fixed;
+ }
+
+ public int hashCode()
+ {
+ return value;
+ }
+
+ public boolean equals(Object other)
+ {
+ return (other instanceof WhiteSpaceFacet &&
+ ((WhiteSpaceFacet) other).value == value);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/AnyNameNameClass.java b/libjava/classpath/gnu/xml/validation/relaxng/AnyNameNameClass.java
new file mode 100644
index 000000000..7b27a3c98
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/AnyNameNameClass.java
@@ -0,0 +1,57 @@
+/* AnyNameNameClass.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG anyName element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class AnyNameNameClass
+ extends NameClass
+{
+
+ NameClass exceptNameClass;
+
+ boolean matchesName(String uri, String localName)
+ {
+ return (exceptNameClass == null) ? true :
+ !exceptNameClass.matchesName(uri, localName);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/AttributePattern.java b/libjava/classpath/gnu/xml/validation/relaxng/AttributePattern.java
new file mode 100644
index 000000000..54e414dc5
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/AttributePattern.java
@@ -0,0 +1,52 @@
+/* AttributePattern.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG attribute element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class AttributePattern
+ extends Pattern
+{
+
+ NameClass nameClass;
+ Pattern pattern;
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/ChoiceNameClass.java b/libjava/classpath/gnu/xml/validation/relaxng/ChoiceNameClass.java
new file mode 100644
index 000000000..9c762b926
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/ChoiceNameClass.java
@@ -0,0 +1,58 @@
+/* ChoiceNameClass.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG choice element (in the context of a name class).
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class ChoiceNameClass
+ extends NameClass
+{
+
+ NameClass name1;
+ NameClass name2;
+
+ boolean matchesName(String uri, String localName)
+ {
+ return name1.matchesName(uri, localName) ||
+ name2.matchesName(uri, localName);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/ChoicePattern.java b/libjava/classpath/gnu/xml/validation/relaxng/ChoicePattern.java
new file mode 100644
index 000000000..48c96b2fb
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/ChoicePattern.java
@@ -0,0 +1,52 @@
+/* ChoicePattern.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG choice element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class ChoicePattern
+ extends Pattern
+{
+
+ Pattern pattern1;
+ Pattern pattern2;
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/DataPattern.java b/libjava/classpath/gnu/xml/validation/relaxng/DataPattern.java
new file mode 100644
index 000000000..f4e36c726
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/DataPattern.java
@@ -0,0 +1,59 @@
+/* DataPattern.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+import java.util.LinkedList;
+import java.util.List;
+import org.relaxng.datatype.Datatype;
+import org.relaxng.datatype.DatatypeLibrary;
+
+/**
+ * A RELAX NG data element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class DataPattern
+ extends Pattern
+{
+
+ Datatype type;
+ DatatypeLibrary datatypeLibrary;
+ List params = new LinkedList();
+ Pattern exceptPattern;
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/Define.java b/libjava/classpath/gnu/xml/validation/relaxng/Define.java
new file mode 100644
index 000000000..ffb1d41ee
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/Define.java
@@ -0,0 +1,51 @@
+/* Define.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG define.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class Define
+{
+
+ String name;
+ ElementPattern element;
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/ElementPattern.java b/libjava/classpath/gnu/xml/validation/relaxng/ElementPattern.java
new file mode 100644
index 000000000..e02731968
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/ElementPattern.java
@@ -0,0 +1,52 @@
+/* ElementPattern.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class ElementPattern
+ extends Pattern
+{
+
+ NameClass nameClass;
+ Pattern pattern;
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/EmptyPattern.java b/libjava/classpath/gnu/xml/validation/relaxng/EmptyPattern.java
new file mode 100644
index 000000000..13c2d3f61
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/EmptyPattern.java
@@ -0,0 +1,51 @@
+/* EmptyPattern.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG empty element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class EmptyPattern
+ extends Pattern
+{
+
+ static final EmptyPattern INSTANCE = new EmptyPattern();
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/FullSyntaxBuilder.java b/libjava/classpath/gnu/xml/validation/relaxng/FullSyntaxBuilder.java
new file mode 100644
index 000000000..bb73c4f38
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/FullSyntaxBuilder.java
@@ -0,0 +1,1650 @@
+/* FullSyntaxBuilder.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.DatatypeLibrary;
+import org.relaxng.datatype.helpers.DatatypeLibraryLoader;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import org.xml.sax.SAXException;
+
+import gnu.xml.stream.XMLParser;
+
+/**
+ * Parses a RELAX NG XML DOM tree, constructing a compiled internal
+ * representation.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class FullSyntaxBuilder
+{
+
+ /**
+ * Complete vocabulary (elements and attributes) of the full syntax.
+ */
+ static final Map VOCABULARY = new HashMap();
+ static final Set STRIPPED_ATTRIBUTES = new HashSet();
+ static final Set PATTERN_ELEMENTS = new HashSet();
+ static
+ {
+ Set elementAttrs = Collections.singleton("name");
+ Set dataAttrs = new HashSet();
+ dataAttrs.add("type");
+ dataAttrs.add("datatypeLibrary");
+ Set valueAttrs = new HashSet();
+ valueAttrs.add("type");
+ valueAttrs.add("datatypeLibrary");
+ valueAttrs.add("ns");
+ Set externalAttrs = Collections.singleton("href");
+ Set startAttrs = Collections.singleton("combine");
+ Set defineAttrs = new HashSet();
+ defineAttrs.add("name");
+ defineAttrs.add("combine");
+ Set nsAttrs = Collections.singleton("ns");
+
+ VOCABULARY.put("element", elementAttrs);
+ VOCABULARY.put("attribute", elementAttrs);
+ VOCABULARY.put("group", Collections.EMPTY_SET);
+ VOCABULARY.put("interleave", Collections.EMPTY_SET);
+ VOCABULARY.put("choice", Collections.EMPTY_SET);
+ VOCABULARY.put("optional", Collections.EMPTY_SET);
+ VOCABULARY.put("zeroOrMore", Collections.EMPTY_SET);
+ VOCABULARY.put("oneOrMore", Collections.EMPTY_SET);
+ VOCABULARY.put("list", Collections.EMPTY_SET);
+ VOCABULARY.put("mixed", Collections.EMPTY_SET);
+ VOCABULARY.put("ref", elementAttrs);
+ VOCABULARY.put("parentRef", elementAttrs);
+ VOCABULARY.put("empty", Collections.EMPTY_SET);
+ VOCABULARY.put("text", Collections.EMPTY_SET);
+ VOCABULARY.put("value", valueAttrs);
+ VOCABULARY.put("data", dataAttrs);
+ VOCABULARY.put("notAllowed", Collections.EMPTY_SET);
+ VOCABULARY.put("externalRef", externalAttrs);
+ VOCABULARY.put("grammar", Collections.EMPTY_SET);
+ VOCABULARY.put("param", elementAttrs);
+ VOCABULARY.put("except", Collections.EMPTY_SET);
+ VOCABULARY.put("div", Collections.EMPTY_SET);
+ VOCABULARY.put("include", externalAttrs);
+ VOCABULARY.put("start", startAttrs);
+ VOCABULARY.put("define", defineAttrs);
+ VOCABULARY.put("name", nsAttrs);
+ VOCABULARY.put("anyName", Collections.EMPTY_SET);
+ VOCABULARY.put("nsName", nsAttrs);
+
+ STRIPPED_ATTRIBUTES.add("name");
+ STRIPPED_ATTRIBUTES.add("type");
+ STRIPPED_ATTRIBUTES.add("combine");
+
+ PATTERN_ELEMENTS.add("element");
+ PATTERN_ELEMENTS.add("attribute");
+ PATTERN_ELEMENTS.add("group");
+ PATTERN_ELEMENTS.add("interleave");
+ PATTERN_ELEMENTS.add("choice");
+ PATTERN_ELEMENTS.add("optional");
+ PATTERN_ELEMENTS.add("zeroOrMore");
+ PATTERN_ELEMENTS.add("oneOrMore");
+ PATTERN_ELEMENTS.add("list");
+ PATTERN_ELEMENTS.add("mixed");
+ PATTERN_ELEMENTS.add("ref");
+ PATTERN_ELEMENTS.add("parentRef");
+ PATTERN_ELEMENTS.add("empty");
+ PATTERN_ELEMENTS.add("text");
+ PATTERN_ELEMENTS.add("value");
+ PATTERN_ELEMENTS.add("data");
+ PATTERN_ELEMENTS.add("notAllowed");
+ PATTERN_ELEMENTS.add("externalRef");
+ PATTERN_ELEMENTS.add("grammar");
+ }
+
+ private Set urls; // recursion checking
+ private int refCount; // creation of ref names
+ private Map datatypeLibraries;
+
+ /**
+ * Parse the specified document into a grammar.
+ */
+ synchronized Grammar parse(Document doc)
+ throws IOException
+ {
+ urls = new HashSet();
+ refCount = 1;
+
+ doc.normalizeDocument(); // Normalize XML document
+ transform(doc); // Apply transformation rules to provide simple syntax
+
+ // 4.18. grammar element
+ Element p = doc.getDocumentElement();
+ Element grammar =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI, "grammar");
+ Element start =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI, "start");
+ doc.removeChild(p);
+ doc.appendChild(grammar);
+ grammar.appendChild(start);
+ start.appendChild(p);
+ transformGrammar(grammar, p);
+ Element define = getNextSiblingElement(start);
+ while (define != null)
+ {
+ Element next = getNextSiblingElement(define);
+ String name = define.getAttribute("new-name");
+ if (name != null)
+ {
+ define.setAttribute("name", name);
+ define.removeAttribute("new-name");
+ }
+ else
+ grammar.removeChild(define); // unreferenced
+ define = next;
+ }
+
+ // 4.19. define and ref elements
+ Set allDefines = new HashSet(), reachableDefines = new HashSet();
+ getDefines(allDefines, grammar, grammar, false);
+ getDefines(reachableDefines, grammar, start, true);
+ allDefines.removeAll(reachableDefines);
+ for (Iterator i = allDefines.iterator(); i.hasNext(); )
+ {
+ // remove unreachable defines
+ Element d = (Element) i.next();
+ Node parent = d.getParentNode();
+ parent.removeChild(d);
+ }
+ // replace all elements that are not children of defines by refs to new
+ // defines
+ Set elements = new HashSet();
+ getElements(elements, grammar, grammar);
+ for (Iterator i = elements.iterator(); i.hasNext(); )
+ {
+ Element element = (Element) i.next();
+ Node parent = element.getParentNode();
+ if (!reachableDefines.contains(parent))
+ {
+ define =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI, "define");
+ Element ref =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI, "ref");
+ String name = createRefName();
+ define.setAttribute("name", name);
+ ref.setAttribute("name", name);
+ parent.insertBefore(ref, element);
+ define.appendChild(element);
+ grammar.appendChild(define);
+ reachableDefines.add(define);
+ }
+ }
+ // Get defines that don't have element children
+ for (Iterator i = reachableDefines.iterator(); i.hasNext(); )
+ {
+ Element d = (Element) i.next();
+ Element child = getFirstChildElement(d);
+ if (child != null && "element".equals(child.getLocalName()))
+ i.remove();
+ }
+ // Expand refs that refer to these defines
+ expandRefs(reachableDefines, grammar);
+ // Remove any defines that don't have element children
+ for (Iterator i = reachableDefines.iterator(); i.hasNext(); )
+ {
+ Element d = (Element) i.next();
+ Node parent = d.getParentNode();
+ parent.removeChild(d);
+ }
+
+ transform2(p); // Apply second stage transformation rules
+
+ Grammar ret = parseGrammar(grammar);
+ datatypeLibraries = null; // free datatype libraries cache
+ return ret;
+ }
+
+ private void getDefines(Set defines, Element grammar, Element node,
+ boolean followRefs)
+ {
+ String elementName = node.getLocalName();
+ if ("define".equals(elementName))
+ defines.add(node);
+ else if ("ref".equals(elementName) && followRefs)
+ {
+ String rname = node.getAttribute("name");
+ Element define = getFirstChildElement(grammar);
+ define = getNextSiblingElement(define);
+ while (define != null)
+ {
+ String dname = define.getAttribute("name");
+ if (rname.equals(dname))
+ {
+ getDefines(defines, grammar, node, followRefs);
+ break;
+ }
+ define = getNextSiblingElement(define);
+ }
+ }
+ for (Element child = getFirstChildElement(node); child != null;
+ child = getNextSiblingElement(child))
+ getDefines(defines, grammar, child, followRefs);
+ }
+
+ private void getElements(Set elements, Element grammar, Element node)
+ {
+ String elementName = node.getLocalName();
+ if ("element".equals(elementName))
+ elements.add(node);
+ for (Element child = getFirstChildElement(node); child != null;
+ child = getNextSiblingElement(child))
+ getElements(elements, grammar, child);
+ }
+
+ private void expandRefs(Set defines, Element node)
+ throws GrammarException
+ {
+ String elementName = node.getLocalName();
+ if ("ref".equals(elementName))
+ {
+ String rname = node.getAttribute("name");
+ for (Iterator i = defines.iterator(); i.hasNext(); )
+ {
+ Element define = (Element) i.next();
+ String dname = define.getAttribute("name");
+ if (rname.equals(dname))
+ {
+ Element child = getFirstChildElement(define);
+ forbidRefs(child, rname);
+ Element refChild = (Element) child.cloneNode(true);
+ Node parent = node.getParentNode();
+ parent.insertBefore(refChild, node);
+ parent.removeChild(node);
+ node = refChild;
+ break;
+ }
+ }
+ }
+ for (Element child = getFirstChildElement(node); child != null;
+ child = getNextSiblingElement(child))
+ expandRefs(defines, child);
+ }
+
+ private void forbidRefs(Element node, String name)
+ throws GrammarException
+ {
+ String elementName = node.getLocalName();
+ if ("ref".equals(elementName))
+ {
+ String rname = node.getAttribute("name");
+ if (name.equals(rname))
+ throw new GrammarException("cannot expand ref with name '" + name +
+ "' due to circularity");
+ }
+ for (Element child = getFirstChildElement(node); child != null;
+ child = getNextSiblingElement(child))
+ forbidRefs(child, name);
+ }
+
+ private void transform(Node node)
+ throws IOException
+ {
+ Node parent = node.getParentNode();
+ switch (node.getNodeType())
+ {
+ case Node.ELEMENT_NODE:
+ // 4.1 Annotations
+ String elementNs = node.getNamespaceURI();
+ String elementName = node.getLocalName();
+ if (!XMLConstants.RELAXNG_NS_URI.equals(elementNs) ||
+ !VOCABULARY.containsKey(elementName))
+ parent.removeChild(node);
+ else
+ {
+ Set allowedAttrs = (Set) VOCABULARY.get(elementName);
+ NamedNodeMap attrs = node.getAttributes();
+ int len = attrs.getLength();
+ for (int i = len - 1; i >= 0; i--)
+ {
+ Node attr = attrs.item(i);
+ String attrNs = attr.getNamespaceURI();
+ String attrName = attr.getLocalName();
+ if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(attrNs))
+ continue; // ignore namespace nodes
+ if (!(XMLConstants.RELAXNG_NS_URI.equals(attrNs) ||
+ attrNs == null) ||
+ !allowedAttrs.contains(attrName))
+ attrs.removeNamedItemNS(attrNs, attrName);
+ else
+ {
+ // 4.2 Whitespace
+ if (STRIPPED_ATTRIBUTES.contains(attrName))
+ attr.setNodeValue(attr.getNodeValue().trim());
+ // 4.3 datatypeLibrary attribute
+ else if ("datatypeLibrary".equals(attrName))
+ {
+ String dl = attr.getNodeValue();
+ attr.setNodeValue(escapeURL(dl));
+ }
+ // 4.5. href attribute
+ else if ("href".equals(attrName))
+ {
+ String href = attr.getNodeValue();
+ href = XMLParser.absolutize(node.getBaseURI(),
+ escapeURL(href));
+ attr.setNodeValue(href);
+ }
+ }
+ }
+ // 4.3 datatypeLibrary attribute
+ if ("data".equals(elementName) || "value".equals(elementName))
+ {
+ Element element = (Element) node;
+ String dl = element.getAttribute("datatypeLibrary");
+ if (dl == null)
+ {
+ Node p = parent;
+ while (dl == null && p != null &&
+ p.getNodeType() == Node.ELEMENT_NODE)
+ {
+ dl = ((Element) p)
+ .getAttribute("datatypeLibrary");
+ p = p.getParentNode();
+ }
+ if (dl == null)
+ dl = "";
+ element.setAttribute("datatypeLibrary", dl);
+ }
+ // 4.4. type attribute of value element
+ if ("value".equals(elementName))
+ {
+ String type = element.getAttribute("type");
+ if (type == null)
+ {
+ element.setAttribute("type", "token");
+ element.setAttribute("datatypeLibrary", "");
+ }
+ }
+ // 4.16. Constraints
+ // TODO validate type
+ }
+ // 4.6. externalRef element
+ else if ("externalRef".equals(elementName))
+ {
+ Element externalRef = (Element) node;
+ String href = externalRef.getAttribute("href");
+ // check for recursion
+ if (urls.contains(href))
+ throw new GrammarException("recursive href");
+ urls.add(href);
+ Element element = resolve(href);
+ String eNs = element.getNamespaceURI();
+ String eName = element.getLocalName();
+ if (!(XMLConstants.RELAXNG_NS_URI.equals(eNs) ||
+ eNs == null) ||
+ !PATTERN_ELEMENTS.contains(eName))
+ throw new GrammarException("externally referenced element " +
+ "is not a pattern");
+ transform(element);
+ urls.remove(href);
+ String ns = element.getAttribute("ns");
+ if (ns != null)
+ element.setAttribute("ns",
+ externalRef.getAttribute("ns"));
+ element = (Element) externalRef.getOwnerDocument()
+ .importNode(element, true);
+ parent.replaceChild(element, externalRef);
+ return;
+ }
+ // 4.7 include element
+ else if ("include".equals(elementName))
+ {
+ Element include = (Element) node;
+ String href = include.getAttribute("href");
+ // check for recursion
+ if (urls.contains(href))
+ throw new GrammarException("recursive href");
+ urls.add(href);
+ Element element = resolve(href);
+ String eNs = element.getNamespaceURI();
+ String eName = element.getLocalName();
+ if (!(XMLConstants.RELAXNG_NS_URI.equals(eNs) ||
+ eNs == null) ||
+ !"grammar".equals(eName))
+ throw new GrammarException("included element is not " +
+ "a grammar");
+
+ transform(element);
+ urls.remove(href);
+ // handle components
+ List includeComponents = getComponents(include);
+ List grammarComponents = getComponents(element);
+ for (Iterator i = includeComponents.iterator(); i.hasNext(); )
+ {
+ Element comp = (Element) i.next();
+ String compName = comp.getLocalName();
+ if ("start".equals(compName))
+ {
+ boolean found = false;
+ for (Iterator j = grammarComponents.iterator();
+ j.hasNext(); )
+ {
+ Element c2 = (Element) j.next();
+ if ("start".equals(c2.getLocalName()))
+ {
+ c2.getParentNode().removeChild(c2);
+ found = true;
+ }
+ }
+ if (!found)
+ throw new GrammarException("no start component in " +
+ "included grammar");
+ }
+ else if ("define".equals(compName))
+ {
+ String name = comp.getAttribute("name");
+ boolean found = false;
+ for (Iterator j = grammarComponents.iterator();
+ j.hasNext(); )
+ {
+ Element c2 = (Element) j.next();
+ if ("define".equals(c2.getLocalName()) &&
+ name.equals(c2.getAttribute("name")))
+ {
+ c2.getParentNode().removeChild(c2);
+ found = true;
+ }
+ }
+ if (!found)
+ throw new GrammarException("no define component " +
+ "with name '" + name +
+ "' in included grammar");
+ }
+ }
+ // transform to div element
+ Document doc = include.getOwnerDocument();
+ Element includeDiv =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI, "div");
+ Element grammarDiv =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI, "div");
+ // XXX copy include non-href attributes (none defined?)
+ element = (Element) doc.importNode(element, true);
+ Node ctx = element.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ grammarDiv.appendChild(ctx);
+ ctx = next;
+ }
+ includeDiv.appendChild(grammarDiv);
+ ctx = include.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ includeDiv.appendChild(ctx);
+ ctx = next;
+ }
+ parent.replaceChild(includeDiv, include);
+ transform(includeDiv);
+ return;
+ }
+ // 4.8. name attribute of element and attribute elements
+ else if ("attribute".equals(elementName) ||
+ "element".equals(elementName))
+ {
+ Element element = (Element) node;
+ String name = element.getAttribute("name");
+ if (name != null)
+ {
+ Document doc = element.getOwnerDocument();
+ Element n =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI, "name");
+ n.appendChild(doc.createTextNode(name));
+ Node first = element.getFirstChild();
+ if (first != null)
+ element.insertBefore(n, first);
+ else
+ element.appendChild(n);
+ if ("attribute".equals(elementName))
+ {
+ String ns = element.getAttribute("ns");
+ if (ns != null)
+ {
+ n.setAttribute("ns", ns);
+ element.removeAttribute("ns");
+ }
+ }
+ element.removeAttribute("name");
+ }
+ // 4.12. Number of child elements
+ if ("attribute".equals(elementName))
+ {
+ if (getComponents(node).size() == 1)
+ {
+ Document doc = node.getOwnerDocument();
+ Element text =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
+ "text");
+ node.appendChild(text);
+ }
+ }
+ else // element
+ {
+ if (node.getChildNodes().getLength() > 2)
+ {
+ // transform to 2 child elements
+ Document doc = node.getOwnerDocument();
+ Element child =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
+ "group");
+ Node ctx = getFirstChildElement(node);
+ ctx = getNextSiblingElement(ctx); // skip 1
+ while (ctx != null)
+ {
+ Node next = getNextSiblingElement(ctx);
+ child.appendChild(ctx);
+ ctx = next;
+ }
+ node.appendChild(child);
+ }
+ }
+ }
+ // 4.11. div element
+ else if ("div".equals(elementName))
+ {
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ parent.insertBefore(ctx, node);
+ transform(ctx);
+ ctx = next;
+ }
+ parent.removeChild(node);
+ return;
+ }
+ else if ("mixed".equals(elementName))
+ {
+ // 4.12. Number of child elements
+ transformToOneChildElement(node, "group");
+ // 4.13. mixed element
+ Document doc = node.getOwnerDocument();
+ Node interleave =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
+ "interleave");
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ interleave.appendChild(ctx);
+ ctx = next;
+ }
+ Node text =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
+ "text");
+ interleave.appendChild(text);
+ parent.insertBefore(interleave, node);
+ parent.removeChild(node);
+ node = interleave;
+ }
+ else if ("optional".equals(elementName))
+ {
+ // 4.12. Number of child elements
+ transformToOneChildElement(node, "group");
+ // 4.14. optional element
+ Document doc = node.getOwnerDocument();
+ Node choice =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
+ "choice");
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ choice.appendChild(ctx);
+ ctx = next;
+ }
+ Node empty =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
+ "empty");
+ choice.appendChild(empty);
+ parent.insertBefore(choice, node);
+ parent.removeChild(node);
+ node = choice;
+ }
+ else if ("zeroOrMore".equals(elementName))
+ {
+ // 4.12. Number of child elements
+ transformToOneChildElement(node, "group");
+ // 4.15. zeroOrMore element
+ Document doc = node.getOwnerDocument();
+ Node choice =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
+ "choice");
+ Node oneOrMore =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
+ "oneOrMore");
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ oneOrMore.appendChild(ctx);
+ ctx = next;
+ }
+ Node empty =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
+ "empty");
+ choice.appendChild(oneOrMore);
+ choice.appendChild(empty);
+ parent.insertBefore(choice, node);
+ parent.removeChild(node);
+ node = choice;
+ }
+ else if ("list".equals(elementName) ||
+ "oneOrMore".equals(elementName) ||
+ "define".equals(elementName))
+ {
+ // 4.12. Number of child elements
+ transformToOneChildElement(node, "group");
+ }
+ else if ("except".equals(elementName))
+ {
+ // 4.12. Number of child elements
+ transformToOneChildElement(node, "choice");
+ // 4.16. Constraints
+ String parentName = parent.getLocalName();
+ if ("anyName".equals(parentName))
+ forbidDescendants(node, Collections.singleton("anyName"));
+ else if ("nsName".equals(parentName))
+ {
+ Set names = new HashSet();
+ names.add("nsName");
+ names.add("anyName");
+ forbidDescendants(node, names);
+ }
+ }
+ else if ("choice".equals(elementName) ||
+ "group".equals(elementName) ||
+ "interleave".equals(elementName))
+ {
+ // 4.12. Number of child elements
+ Node ctx = getFirstChildElement(node);
+ Node next = getNextSiblingElement(ctx);
+ if (next == null)
+ {
+ // replace
+ parent.insertBefore(ctx, node);
+ parent.removeChild(node);
+ transform(ctx);
+ return;
+ }
+ else
+ {
+ // transform to 2 child elements
+ Node next2 = getNextSiblingElement(next);
+ if (next2 != null)
+ {
+ Document doc = node.getOwnerDocument();
+ Node child =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
+ elementName);
+ child.appendChild(ctx);
+ child.appendChild(next);
+ node.insertBefore(next2, child);
+ transform(node); // recurse
+ }
+ }
+ }
+ // 4.17. combine attribute
+ else if ("grammar".equals(elementName))
+ {
+ String combine = null;
+ List nodes = new LinkedList();
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ if ("start".equals(ctx.getLocalName()))
+ {
+ String c = ((Element) ctx).getAttribute("combine");
+ if (combine != null && !combine.equals(c))
+ throw new GrammarException("multiple start elements "+
+ "but no combine attribute");
+ combine = c;
+ nodes.add(ctx);
+ }
+ ctx = next;
+ }
+ if (!nodes.isEmpty())
+ combineNodes(node, combine, "start", nodes);
+ // defines
+ Map defines = new HashMap();
+ Map defineCombines = new HashMap();
+ ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ if ("define".equals(ctx.getLocalName()))
+ {
+ String name = ((Element) ctx).getAttribute("name");
+ combine = (String) defineCombines.get(name);
+ String c = ((Element) ctx).getAttribute("combine");
+ if (combine != null && !combine.equals(c))
+ throw new GrammarException("multiple define " +
+ "elements with name '"+
+ name + "' but no " +
+ "combine attribute");
+ defineCombines.put(name, c);
+ nodes = (List) defines.get(name);
+ if (nodes == null)
+ {
+ nodes = new LinkedList();
+ defines.put(name, nodes);
+ }
+ nodes.add(ctx);
+ }
+ ctx = next;
+ }
+ for (Iterator i = defines.keySet().iterator(); i.hasNext(); )
+ {
+ String name = (String) i.next();
+ combine = (String) defineCombines.get(name);
+ nodes = (List) defines.get(name);
+ if (!nodes.isEmpty())
+ combineNodes(node, combine, "define", nodes);
+ }
+ }
+ // 4.9. ns attribute
+ if ("name".equals(elementName) ||
+ "nsName".equals(elementName) ||
+ "value".equals(elementName))
+ {
+ Element element = (Element) node;
+ String ns = element.getAttribute("ns");
+ if (ns == null)
+ {
+ Node ctx = parent;
+ while (ns == null && ctx != null &&
+ ctx.getNodeType() == Node.ELEMENT_NODE)
+ {
+ ns = ((Element) ctx).getAttribute("ns");
+ ctx = ctx.getParentNode();
+ }
+ element.setAttribute("ns", (ns == null) ? "" : ns);
+ }
+ if ("name".equals(elementName))
+ {
+ // 4.10. QNames
+ String name = element.getTextContent();
+ int ci = name.indexOf(':');
+ if (ci != -1)
+ {
+ String prefix = name.substring(0, ci);
+ element.setTextContent(name.substring(ci + 1));
+ ns = element.lookupNamespaceURI(prefix);
+ element.setAttribute("ns", (ns == null) ? "" : ns);
+ }
+ // 4.16. Constraints
+ if (isDescendantOfFirstChildOfAttribute(element) &&
+ "".equals(element.getAttribute("ns")) &&
+ "xmlns".equals(element.getTextContent()))
+ throw new GrammarException("name cannot be xmlns");
+ }
+ else if ("nsName".equals(elementName))
+ {
+ // 4.16. Constraints
+ if (isDescendantOfFirstChildOfAttribute(element) &&
+ "http://www.w3.org/2000/xmlns"
+ .equals(element.getAttribute("ns")))
+ throw new GrammarException("nsName cannot be XMLNS URI");
+ }
+ }
+ }
+
+ break;
+ case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ // 4.2 Whitespace
+ String parentName = parent.getLocalName();
+ if ("name".equals(parentName))
+ node.setNodeValue(node.getNodeValue().trim());
+ if (!"param".equals(parentName) &&
+ !"value".equals(parentName) &&
+ isWhitespace(node.getNodeValue()))
+ parent.removeChild(node);
+ break;
+ case Node.DOCUMENT_NODE:
+ break;
+ default:
+ parent.removeChild(node);
+ }
+ // Transform children
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ transform(ctx);
+ ctx = next;
+ }
+ }
+
+ /**
+ * Transforms the schema to place all defines under the top-level grammar
+ * element and replace all other grammar elements by their start child.
+ */
+ private void transformGrammar(Node grammar, Node node)
+ throws GrammarException
+ {
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ String elementName = node.getLocalName();
+ if ("grammar".equals(elementName))
+ {
+ handleRefs(grammar, node, node);
+ Node start = null;
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ String childName = ctx.getLocalName();
+ if ("define".equals(childName))
+ grammar.appendChild(ctx);
+ else if ("start".equals(childName))
+ start = ctx;
+ ctx = next;
+ }
+ if (start == null)
+ throw new GrammarException("no start element for grammar");
+ Node p = getFirstChildElement(start);
+ Node parent = node.getParentNode();
+ parent.insertBefore(p, node);
+ parent.removeChild(node);
+ node = p;
+ }
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ transformGrammar(grammar, ctx);
+ ctx = next;
+ }
+ }
+ }
+
+ /**
+ * Checks that all references in the specified grammar match a define in
+ * the grammar.
+ */
+ private void handleRefs(Node grammar1, Node grammar2, Node node)
+ throws GrammarException
+ {
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ String elementName = node.getLocalName();
+ if ("ref".equals(elementName) || "parentRef".equals(elementName))
+ {
+ Node grammar = grammar2;
+ if ("parentRef".equals(elementName))
+ grammar = grammar1;
+
+ String name = ((Element) node).getAttribute("name");
+ if (name != null)
+ throw new GrammarException("no name attribute on " +
+ elementName);
+ Node define = null;
+ for (Node ctx = grammar.getFirstChild();
+ define == null && ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ if ("define".equals(ctx.getLocalName()))
+ {
+ String dname = ((Element) ctx).getAttribute("name");
+ if (name.equals(dname))
+ define = ctx;
+ }
+ }
+ if (define == null)
+ throw new GrammarException("no define for '" + name + "'");
+ name = ((Element) define).getAttribute("new-name");
+ if (name == null)
+ {
+ name = createRefName();
+ ((Element) define).setAttribute("new-name", name);
+ }
+ if ("parentRef".equals(elementName))
+ {
+ Document doc = node.getOwnerDocument();
+ Node ref = doc.createElementNS(XMLConstants.RELAXNG_NS_URI,
+ "ref");
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ ref.appendChild(ctx);
+ ctx = next;
+ }
+ Node parent = node.getParentNode();
+ parent.insertBefore(ref, node);
+ parent.removeChild(node);
+ node = ref;
+ }
+ ((Element) node).setAttribute("name", name);
+ }
+ else if ("grammar".equals(elementName))
+ {
+ grammar1 = grammar2;
+ grammar2 = node;
+ }
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ handleRefs(grammar1, grammar2, ctx);
+ ctx = next;
+ }
+ }
+ }
+
+ private String createRefName()
+ {
+ return "ref" + Integer.toString(refCount++);
+ }
+
+ private void transform2(Node node)
+ throws GrammarException
+ {
+ Node parent = node.getParentNode();
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ String elementName = node.getLocalName();
+ // 4.20. notAllowed element
+ if ("notAllowed".equals(elementName))
+ {
+ String parentName = parent.getLocalName();
+ if ("attribute".equals(parentName) ||
+ "list".equals(parentName) ||
+ "group".equals(parentName) ||
+ "interleave".equals(parentName) ||
+ "oneOrMore".equals(parentName))
+ {
+ Node pp = parent.getParentNode();
+ pp.insertBefore(node, parent);
+ pp.removeChild(parent);
+ transform2(node); // apply recursively
+ return;
+ }
+ else if ("choice".equals(parentName))
+ {
+ Node p1 = getFirstChildElement(parent);
+ Node p2 = getNextSiblingElement(p1);
+ if (p1 == null || p2 == null)
+ throw new GrammarException("choice does not have two " +
+ "children");
+ String p1Name = p1.getLocalName();
+ String p2Name = p2.getLocalName();
+ Node pp = parent.getParentNode();
+ if ("notAllowed".equals(p1Name) &&
+ "notAllowed".equals(p2Name))
+ {
+ pp.insertBefore(p1, parent);
+ pp.removeChild(parent);
+ transform2(p1); //apply recursively
+ return;
+ }
+ else if ("notAllowed".equals(p1Name))
+ {
+ pp.insertBefore(p2, parent);
+ pp.removeChild(parent);
+ transform2(p2);
+ return;
+ }
+ else
+ {
+ pp.insertBefore(p1, parent);
+ pp.removeChild(parent);
+ transform2(p1);
+ return;
+ }
+ }
+ else if ("except".equals(parentName))
+ {
+ Node pp = parent.getParentNode();
+ pp.removeChild(parent);
+ return;
+ }
+ }
+ // 4.21. empty element
+ else if ("empty".equals(elementName))
+ {
+ String parentName = parent.getLocalName();
+ if ("group".equals(parentName) ||
+ "interleave".equals(parentName))
+ {
+ Node p1 = getFirstChildElement(parent);
+ Node p2 = getNextSiblingElement(p1);
+ if (p1 == null || p2 == null)
+ throw new GrammarException(parentName + " does not have " +
+ "two children");
+ String p1Name = p1.getLocalName();
+ String p2Name = p2.getLocalName();
+ Node pp = parent.getParentNode();
+ if ("empty".equals(p1Name) &&
+ "empty".equals(p2Name))
+ {
+ pp.insertBefore(p1, parent);
+ pp.removeChild(parent);
+ transform2(p1);
+ return;
+ }
+ else if ("empty".equals(p1Name))
+ {
+ pp.insertBefore(p2, parent);
+ pp.removeChild(parent);
+ transform2(p2);
+ return;
+ }
+ else
+ {
+ pp.insertBefore(p1, parent);
+ pp.removeChild(parent);
+ transform2(p1);
+ return;
+ }
+ }
+ else if ("choice".equals(parentName))
+ {
+ Node p1 = getFirstChildElement(parent);
+ Node p2 = getNextSiblingElement(p1);
+ if (p1 == null || p2 == null)
+ throw new GrammarException(parentName + " does not have " +
+ "two children");
+ String p1Name = p1.getLocalName();
+ String p2Name = p2.getLocalName();
+ Node pp = parent.getParentNode();
+ if ("empty".equals(p1Name) &&
+ "empty".equals(p2Name))
+ {
+ pp.insertBefore(p1, parent);
+ pp.removeChild(parent);
+ transform2(p1);
+ return;
+ }
+ }
+ else if ("oneOrMore".equals(parentName))
+ {
+ Node pp = parent.getParentNode();
+ pp.insertBefore(node, parent);
+ pp.removeChild(parent);
+ transform2(node);
+ return;
+ }
+ }
+ Node ctx = node.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ transform2(ctx);
+ ctx = next;
+ }
+ }
+ }
+
+ private static boolean isWhitespace(String text)
+ {
+ int len = text.length();
+ for (int i = 0; i < len; i++)
+ {
+ char c = text.charAt(i);
+ if (c != ' ' && c != '\t' && c != '\n' && c != '\r')
+ return false;
+ }
+ return true;
+ }
+
+ private static String escapeURL(String url)
+ {
+ try
+ {
+ return URLEncoder.encode(url, "UTF-8");
+ }
+ catch (UnsupportedEncodingException e)
+ {
+ RuntimeException e2 = new RuntimeException("UTF-8 is unsupported");
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+ /**
+ * Resolve a URL to an element, as described in section 4.5.
+ */
+ private static Element resolve(String url)
+ throws IOException
+ {
+ try
+ {
+ URL u = new URL(url);
+ InputStream in = u.openStream();
+ DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
+ f.setNamespaceAware(true);
+ f.setCoalescing(true);
+ f.setExpandEntityReferences(true);
+ f.setIgnoringComments(true);
+ f.setIgnoringElementContentWhitespace(true);
+ DocumentBuilder b = f.newDocumentBuilder();
+ Document doc = b.parse(in, url);
+ in.close();
+ String fragment = u.getRef();
+ if (fragment != null)
+ return doc.getElementById(fragment);
+ return doc.getDocumentElement();
+ }
+ catch (SAXException e)
+ {
+ IOException e2 = new IOException("error parsing included element");
+ e2.initCause(e);
+ throw e2;
+ }
+ catch (ParserConfigurationException e)
+ {
+ IOException e2 = new IOException("error parsing included element");
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+ /**
+ * Returns the "components" of an element, as described in section 4.7.
+ */
+ private List getComponents(Node node)
+ {
+ List ret = new LinkedList();
+ for (Node ctx = node.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ if (ctx.getNodeType() != Node.ELEMENT_NODE)
+ continue;
+ String ns = ctx.getNamespaceURI();
+ if (ns != null && !ns.equals(XMLConstants.RELAXNG_NS_URI))
+ continue;
+ String name = ctx.getLocalName();
+ if ("div".equals(name))
+ ret.addAll(getComponents(ctx));
+ else if (VOCABULARY.containsKey(name))
+ ret.add(ctx);
+ }
+ return ret;
+ }
+
+ private static void transformToOneChildElement(Node node, String name)
+ {
+ if (node.getChildNodes().getLength() < 2)
+ return;
+ Document doc = node.getOwnerDocument();
+ Element child = doc.createElementNS(XMLConstants.RELAXNG_NS_URI, name);
+ Node ctx = getFirstChildElement(node);
+ while (ctx != null)
+ {
+ Node next = getNextSiblingElement(ctx);
+ child.appendChild(ctx);
+ ctx = next;
+ }
+ node.appendChild(child);
+ }
+
+ private static Element getFirstChildElement(Node node)
+ {
+ Node ctx = node.getFirstChild();
+ while (ctx != null && ctx.getNodeType() != Node.ELEMENT_NODE)
+ ctx = ctx.getNextSibling();
+ return (Element) ctx;
+ }
+
+ private static Element getNextSiblingElement(Node node)
+ {
+ Node ctx = node.getNextSibling();
+ while (ctx != null && ctx.getNodeType() != Node.ELEMENT_NODE)
+ ctx = ctx.getNextSibling();
+ return (Element) ctx;
+ }
+
+ private static void forbidDescendants(Node node, Set names)
+ throws GrammarException
+ {
+ for (Node ctx = node.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ String ns = ctx.getNamespaceURI();
+ if (!XMLConstants.RELAXNG_NS_URI.equals(ns))
+ continue;
+ String name = ctx.getLocalName();
+ if (names.contains(name))
+ throw new GrammarException("name not allowed: " + name);
+ forbidDescendants(ctx, names);
+ }
+ }
+
+ private static boolean isDescendantOfFirstChildOfAttribute(Node node)
+ {
+ Node child = node;
+ Node parent = node.getParentNode();
+ while (parent != null && !"attribute".equals(parent.getLocalName()))
+ {
+ child = parent;
+ parent = child.getParentNode();
+ }
+ if (parent == null)
+ return false;
+ Node firstChild = getFirstChildElement(parent);
+ return firstChild == child;
+ }
+
+ private static void combineNodes(Node node, String combine, String name,
+ List nodes)
+ {
+ Document doc = node.getOwnerDocument();
+ Node child =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI, name);
+ Node combineNode =
+ doc.createElementNS(XMLConstants.RELAXNG_NS_URI, combine);
+ child.appendChild(combineNode);
+ boolean inserted = false;
+ for (Iterator i = nodes.iterator(); i.hasNext(); )
+ {
+ Node startNode = (Node) i.next();
+ if (!inserted)
+ {
+ node.insertBefore(child, startNode);
+ inserted = true;
+ }
+ Node ctx = startNode.getFirstChild();
+ while (ctx != null)
+ {
+ Node next = ctx.getNextSibling();
+ combineNode.appendChild(ctx);
+ ctx = next;
+ }
+ node.removeChild(startNode);
+ }
+ }
+
+ Grammar parseGrammar(Element node)
+ throws GrammarException
+ {
+ checkName(node, "grammar");
+ Grammar grammar = new Grammar();
+ Element start = getFirstChildElement(node);
+ grammar.start = parsePattern(getFirstChildElement(start));
+ for (Element define = getNextSiblingElement(start); define != null;
+ define = getNextSiblingElement(define))
+ grammar.defines.add(parseDefine(define));
+ return grammar;
+ }
+
+ Define parseDefine(Element node)
+ throws GrammarException
+ {
+ checkName(node, "define");
+ Define define = new Define();
+ define.name = node.getAttribute("name");
+ define.element = parseElement(getFirstChildElement(node));
+ return define;
+ }
+
+ Pattern parseTop(Element node)
+ throws GrammarException
+ {
+ String name = node.getLocalName();
+ if ("notAllowed".equals(name))
+ return parseNotAllowed(node);
+ return parsePattern(node);
+ }
+
+ Pattern parsePattern(Element node)
+ throws GrammarException
+ {
+ String name = node.getLocalName();
+ if ("empty".equals(name))
+ return parseEmpty(node);
+ return parseNonEmptyPattern(node);
+ }
+
+ Pattern parseNonEmptyPattern(Element node)
+ throws GrammarException
+ {
+ String name = node.getLocalName();
+ if ("text".equals(name))
+ return parseText(node);
+ else if ("data".equals(name))
+ return parseData(node);
+ else if ("value".equals(name))
+ return parseValue(node);
+ else if ("list".equals(name))
+ return parseList(node);
+ else if ("attribute".equals(name))
+ return parseAttribute(node);
+ else if ("ref".equals(name))
+ return parseRef(node);
+ else if ("oneOrMore".equals(name))
+ return parseOneOrMore(node);
+ else if ("choice".equals(name))
+ return parseChoice(node);
+ else if ("group".equals(name))
+ return parseGroup(node);
+ else if ("interleave".equals(name))
+ return parseInterleave(node);
+ throw new GrammarException("invalid pattern: " + name);
+ }
+
+ ElementPattern parseElement(Element node)
+ throws GrammarException
+ {
+ checkName(node, "element");
+ ElementPattern element = new ElementPattern();
+ Element nameClass = getFirstChildElement(node);
+ element.nameClass = parseNameClass(nameClass);
+ element.pattern = parseTop(getNextSiblingElement(nameClass));
+ return element;
+ }
+
+ NotAllowedPattern parseNotAllowed(Element node)
+ throws GrammarException
+ {
+ checkName(node, "notAllowed");
+ return NotAllowedPattern.INSTANCE;
+ }
+
+ EmptyPattern parseEmpty(Element node)
+ throws GrammarException
+ {
+ checkName(node, "empty");
+ return EmptyPattern.INSTANCE;
+ }
+
+ TextPattern parseText(Element node)
+ throws GrammarException
+ {
+ checkName(node, "text");
+ return TextPattern.INSTANCE;
+ }
+
+ DataPattern parseData(Element node)
+ throws GrammarException
+ {
+ checkName(node, "data");
+ DataPattern data = new DataPattern();
+ DatatypeLibrary dl =
+ getDatatypeLibrary(node.getAttribute("datatypeLibrary"));
+ String type = node.getAttribute("type");
+ try
+ {
+ data.type = dl.createDatatype(type);
+ data.datatypeLibrary = dl;
+ }
+ catch (DatatypeException e)
+ {
+ GrammarException e2 = new GrammarException(type);
+ e2.initCause(e);
+ throw e2;
+ }
+ Element ctx = getFirstChildElement(node);
+ while (ctx != null)
+ {
+ Element next = getNextSiblingElement(ctx);
+ String name = ctx.getLocalName();
+ if ("param".equals(name))
+ data.params.add(parseParam(ctx));
+ else if ("except".equals(name) && next == null)
+ data.exceptPattern = parsePattern(getFirstChildElement(ctx));
+ else
+ throw new GrammarException("invalid element: " + name);
+ ctx = next;
+ }
+ return data;
+ }
+
+ Param parseParam(Element node)
+ throws GrammarException
+ {
+ checkName(node, "param");
+ Param param = new Param();
+ param.name = node.getAttribute("name");
+ param.value = node.getTextContent();
+ return param;
+ }
+
+ ValuePattern parseValue(Element node)
+ throws GrammarException
+ {
+ checkName(node, "value");
+ ValuePattern value = new ValuePattern();
+ DatatypeLibrary dl =
+ getDatatypeLibrary(node.getAttribute("datatypeLibrary"));
+ String type = node.getAttribute("type");
+ try
+ {
+ value.type = dl.createDatatype(type);
+ value.datatypeLibrary = dl;
+ }
+ catch (DatatypeException e)
+ {
+ GrammarException e2 = new GrammarException(type);
+ e2.initCause(e);
+ throw e2;
+ }
+ value.ns = node.getAttribute("ns");
+ value.value = node.getTextContent();
+ return value;
+ }
+
+ ListPattern parseList(Element node)
+ throws GrammarException
+ {
+ checkName(node, "list");
+ ListPattern list = new ListPattern();
+ list.pattern = parsePattern(getFirstChildElement(node));
+ return list;
+ }
+
+ AttributePattern parseAttribute(Element node)
+ throws GrammarException
+ {
+ checkName(node, "attribute");
+ AttributePattern attribute = new AttributePattern();
+ Element nameClass = getFirstChildElement(node);
+ attribute.nameClass = parseNameClass(nameClass);
+ attribute.pattern = parsePattern(getNextSiblingElement(nameClass));
+ return attribute;
+ }
+
+ RefPattern parseRef(Element node)
+ throws GrammarException
+ {
+ checkName(node, "ref");
+ RefPattern ref = new RefPattern();
+ ref.name = node.getAttribute("name");
+ return ref;
+ }
+
+ OneOrMorePattern parseOneOrMore(Element node)
+ throws GrammarException
+ {
+ checkName(node, "oneOrMore");
+ OneOrMorePattern oneOrMore = new OneOrMorePattern();
+ oneOrMore.pattern = parseNonEmptyPattern(getFirstChildElement(node));
+ return oneOrMore;
+ }
+
+ ChoicePattern parseChoice(Element node)
+ throws GrammarException
+ {
+ checkName(node, "choice");
+ ChoicePattern choice = new ChoicePattern();
+ Element p1 = getFirstChildElement(node);
+ Element p2 = getNextSiblingElement(p1);
+ choice.pattern1 = parsePattern(p1);
+ choice.pattern2 = parseNonEmptyPattern(p2);
+ return choice;
+ }
+
+ GroupPattern parseGroup(Element node)
+ throws GrammarException
+ {
+ checkName(node, "group");
+ GroupPattern group = new GroupPattern();
+ Element p1 = getFirstChildElement(node);
+ Element p2 = getNextSiblingElement(p1);
+ group.pattern1 = parseNonEmptyPattern(p1);
+ group.pattern2 = parseNonEmptyPattern(p2);
+ return group;
+ }
+
+ InterleavePattern parseInterleave(Element node)
+ throws GrammarException
+ {
+ checkName(node, "interleave");
+ InterleavePattern interleave = new InterleavePattern();
+ Element p1 = getFirstChildElement(node);
+ Element p2 = getNextSiblingElement(p1);
+ interleave.pattern1 = parseNonEmptyPattern(p1);
+ interleave.pattern2 = parseNonEmptyPattern(p2);
+ return interleave;
+ }
+
+ NameClass parseNameClass(Element node)
+ throws GrammarException
+ {
+ String name = node.getLocalName();
+ if ("anyName".equals(name))
+ return parseAnyName(node);
+ else if ("name".equals(name))
+ return parseName(node);
+ else if ("nsName".equals(name))
+ return parseNsName(node);
+ else if ("choice".equals(name))
+ return parseChoiceNameClass(node);
+ throw new GrammarException("invalid name class: " + name);
+ }
+
+ AnyNameNameClass parseAnyName(Element node)
+ throws GrammarException
+ {
+ checkName(node, "anyName");
+ AnyNameNameClass anyName = new AnyNameNameClass();
+ Element except = getFirstChildElement(node);
+ if (except != null) {
+ checkName(except, "except");
+ anyName.exceptNameClass = parseNameClass(getFirstChildElement(except));
+ }
+ return anyName;
+ }
+
+ NameNameClass parseName(Element node)
+ throws GrammarException
+ {
+ checkName(node, "name");
+ NameNameClass name = new NameNameClass();
+ name.ns = node.getAttribute("ns");
+ name.name = node.getTextContent();
+ return name;
+ }
+
+ NSNameNameClass parseNsName(Element node)
+ throws GrammarException
+ {
+ checkName(node, "nsName");
+ NSNameNameClass nsName = new NSNameNameClass();
+ nsName.ns = node.getAttribute("ns");
+ Element except = getFirstChildElement(node);
+ if (except != null) {
+ checkName(except, "except");
+ nsName.exceptNameClass = parseNameClass(getFirstChildElement(except));
+ }
+ return nsName;
+ }
+
+ ChoiceNameClass parseChoiceNameClass(Element node)
+ throws GrammarException
+ {
+ checkName(node, "choice");
+ ChoiceNameClass choice = new ChoiceNameClass();
+ Element c1 = getFirstChildElement(node);
+ Element c2 = getNextSiblingElement(c1);
+ choice.name1 = parseNameClass(c1);
+ choice.name2 = parseNameClass(c2);
+ return choice;
+ }
+
+ void checkName(Element node, String name)
+ throws GrammarException
+ {
+ if (!name.equals(node.getLocalName()))
+ throw new GrammarException("expecting " + name);
+ }
+
+ DatatypeLibrary getDatatypeLibrary(String uri)
+ throws GrammarException
+ {
+ if (datatypeLibraries == null)
+ datatypeLibraries = new HashMap();
+ DatatypeLibrary library = (DatatypeLibrary) datatypeLibraries.get(uri);
+ if (library == null)
+ {
+ library = new DatatypeLibraryLoader().createDatatypeLibrary(uri);
+ if (library == null)
+ throw new GrammarException("Datatype library not supported: " + uri);
+ datatypeLibraries.put(uri, library);
+ }
+ return library;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/Grammar.java b/libjava/classpath/gnu/xml/validation/relaxng/Grammar.java
new file mode 100644
index 000000000..c2407da2b
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/Grammar.java
@@ -0,0 +1,69 @@
+/* Grammar.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+import java.util.LinkedList;
+import java.util.List;
+import javax.xml.validation.Schema;
+import javax.xml.validation.Validator;
+import javax.xml.validation.ValidatorHandler;
+
+/**
+ * A RELAX NG grammar.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class Grammar
+ extends Schema
+{
+
+ Pattern start;
+ List defines = new LinkedList();
+
+ public Validator newValidator()
+ {
+ return new GrammarValidator(this);
+ }
+
+ public ValidatorHandler newValidatorHandler()
+ {
+ // TODO
+ return null;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/GrammarException.java b/libjava/classpath/gnu/xml/validation/relaxng/GrammarException.java
new file mode 100644
index 000000000..167cf6482
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/GrammarException.java
@@ -0,0 +1,56 @@
+/* GrammarException.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+import java.io.IOException;
+
+/**
+ * Exception parsing a grammar.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class GrammarException
+ extends IOException
+{
+
+ GrammarException(String message)
+ {
+ super(message);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/GrammarValidator.java b/libjava/classpath/gnu/xml/validation/relaxng/GrammarValidator.java
new file mode 100644
index 000000000..e4ff3dab4
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/GrammarValidator.java
@@ -0,0 +1,97 @@
+/* GrammarValidator.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+import java.io.IOException;
+import javax.xml.transform.Source;
+import javax.xml.transform.Result;
+import javax.xml.validation.Validator;
+import org.w3c.dom.ls.LSResourceResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+
+/**
+ * RELAX NG validator.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class GrammarValidator
+ extends Validator
+{
+
+ final Grammar grammar;
+ ErrorHandler errorHandler;
+ LSResourceResolver resourceResolver;
+
+ GrammarValidator(Grammar grammar)
+ {
+ this.grammar = grammar;
+ }
+
+ public ErrorHandler getErrorHandler()
+ {
+ return errorHandler;
+ }
+
+ public void setErrorHandler(ErrorHandler errorHandler)
+ {
+ this.errorHandler = errorHandler;
+ }
+
+ public LSResourceResolver getResourceResolver()
+ {
+ return resourceResolver;
+ }
+
+ public void setResourceResolver(LSResourceResolver resourceResolver)
+ {
+ this.resourceResolver = resourceResolver;
+ }
+
+ public void reset()
+ {
+ // TODO
+ }
+
+ public void validate(Source source, Result result)
+ throws SAXException, IOException
+ {
+ // TODO
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/GroupPattern.java b/libjava/classpath/gnu/xml/validation/relaxng/GroupPattern.java
new file mode 100644
index 000000000..b63c7aaa7
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/GroupPattern.java
@@ -0,0 +1,52 @@
+/* GroupPattern.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG group element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class GroupPattern
+ extends Pattern
+{
+
+ Pattern pattern1;
+ Pattern pattern2;
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/InterleavePattern.java b/libjava/classpath/gnu/xml/validation/relaxng/InterleavePattern.java
new file mode 100644
index 000000000..8a877d7af
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/InterleavePattern.java
@@ -0,0 +1,52 @@
+/* InterleavePattern.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG interleave element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class InterleavePattern
+ extends Pattern
+{
+
+ Pattern pattern1;
+ Pattern pattern2;
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/ListPattern.java b/libjava/classpath/gnu/xml/validation/relaxng/ListPattern.java
new file mode 100644
index 000000000..e16d5f6e5
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/ListPattern.java
@@ -0,0 +1,51 @@
+/* ListPattern.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG list element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class ListPattern
+ extends Pattern
+{
+
+ Pattern pattern;
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/NSNameNameClass.java b/libjava/classpath/gnu/xml/validation/relaxng/NSNameNameClass.java
new file mode 100644
index 000000000..2f620c1d0
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/NSNameNameClass.java
@@ -0,0 +1,60 @@
+/* NSNameNameClass.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG nsName element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class NSNameNameClass
+ extends NameClass
+{
+
+ String ns;
+ NameClass exceptNameClass;
+
+ boolean matchesName(String uri, String localName)
+ {
+ if (!ns.equals(uri))
+ return false;
+ return (exceptNameClass == null) ? true :
+ !exceptNameClass.matchesName(uri, localName);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/NameClass.java b/libjava/classpath/gnu/xml/validation/relaxng/NameClass.java
new file mode 100644
index 000000000..0ef9ef131
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/NameClass.java
@@ -0,0 +1,50 @@
+/* NameClass.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG name class.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+abstract class NameClass
+{
+
+ abstract boolean matchesName(String uri, String localName);
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/NameNameClass.java b/libjava/classpath/gnu/xml/validation/relaxng/NameNameClass.java
new file mode 100644
index 000000000..b2d0e04ee
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/NameNameClass.java
@@ -0,0 +1,59 @@
+/* NameNameClass.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG name element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class NameNameClass
+ extends NameClass
+{
+
+ String ns;
+ String name;
+
+ boolean matchesName(String uri, String localName)
+ {
+ if (!ns.equals(uri))
+ return false;
+ return name.equals(localName);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/NotAllowedPattern.java b/libjava/classpath/gnu/xml/validation/relaxng/NotAllowedPattern.java
new file mode 100644
index 000000000..d56afb2d7
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/NotAllowedPattern.java
@@ -0,0 +1,51 @@
+/* NotAllowedPattern.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG notAllowed element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class NotAllowedPattern
+ extends Pattern
+{
+
+ static final NotAllowedPattern INSTANCE = new NotAllowedPattern();
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/OneOrMorePattern.java b/libjava/classpath/gnu/xml/validation/relaxng/OneOrMorePattern.java
new file mode 100644
index 000000000..0545130ad
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/OneOrMorePattern.java
@@ -0,0 +1,51 @@
+/* OneOrMorePattern.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG oneOrMore element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class OneOrMorePattern
+ extends Pattern
+{
+
+ Pattern pattern;
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/Param.java b/libjava/classpath/gnu/xml/validation/relaxng/Param.java
new file mode 100644
index 000000000..65a1b6689
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/Param.java
@@ -0,0 +1,51 @@
+/* Param.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG param element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class Param
+{
+
+ String name;
+ String value;
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/Pattern.java b/libjava/classpath/gnu/xml/validation/relaxng/Pattern.java
new file mode 100644
index 000000000..157f22316
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/Pattern.java
@@ -0,0 +1,47 @@
+/* Pattern.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG pattern.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+abstract class Pattern
+{
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/RELAXNGSchemaFactory.java b/libjava/classpath/gnu/xml/validation/relaxng/RELAXNGSchemaFactory.java
new file mode 100644
index 000000000..c0c9bd887
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/RELAXNGSchemaFactory.java
@@ -0,0 +1,163 @@
+/* RelaxNGSchemaFactory.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+import java.io.IOException;
+import java.net.URL;
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Source;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.ls.LSResourceResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Schema factory for RELAX NG grammars.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class RELAXNGSchemaFactory
+ extends SchemaFactory
+{
+
+ LSResourceResolver resourceResolver;
+ ErrorHandler errorHandler;
+
+ public LSResourceResolver getResourceResolver()
+ {
+ return resourceResolver;
+ }
+
+ public void setResourceResolver(LSResourceResolver resourceResolver)
+ {
+ this.resourceResolver = resourceResolver;
+ }
+
+ public ErrorHandler getErrorHandler()
+ {
+ return this.errorHandler;
+ }
+
+ public void setErrorHandler(ErrorHandler errorHandler)
+ {
+ this.errorHandler = errorHandler;
+ }
+
+ public boolean isSchemaLanguageSupported(String schemaLanguage)
+ {
+ return XMLConstants.RELAXNG_NS_URI.equals(schemaLanguage);
+ }
+
+ public Schema newSchema()
+ throws SAXException
+ {
+ // TODO
+ throw new UnsupportedOperationException();
+ }
+
+ public Schema newSchema(Source[] schemata)
+ throws SAXException
+ {
+ if (schemata == null || schemata.length != 1)
+ throw new IllegalArgumentException("must specify one source");
+ // TODO multiple schemata
+ // TODO compact syntax
+ try
+ {
+ Document doc = getDocument(schemata[0]);
+ FullSyntaxBuilder builder = new FullSyntaxBuilder();
+ return builder.parse(doc);
+ }
+ catch (IOException e)
+ {
+ SAXException e2 = new SAXException(e.getMessage());
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+ private static Document getDocument(Source source)
+ throws SAXException, IOException
+ {
+ if (source instanceof DOMSource)
+ {
+ Node node = ((DOMSource) source).getNode();
+ if (node != null && node instanceof Document)
+ return (Document) node;
+ }
+ String url = source.getSystemId();
+ try
+ {
+ InputSource input = new InputSource(url);
+ if (source instanceof StreamSource)
+ {
+ StreamSource streamSource = (StreamSource) source;
+ input.setByteStream(streamSource.getInputStream());
+ input.setCharacterStream(streamSource.getReader());
+ }
+ if (input.getByteStream() == null &&
+ input.getCharacterStream() == null &&
+ url != null)
+ input.setByteStream(new URL(url).openStream());
+ DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
+ f.setNamespaceAware(true);
+ f.setCoalescing(true);
+ f.setExpandEntityReferences(true);
+ f.setIgnoringComments(true);
+ f.setIgnoringElementContentWhitespace(true);
+ DocumentBuilder b = f.newDocumentBuilder();
+ return b.parse(input);
+ }
+ catch (ParserConfigurationException e)
+ {
+ SAXException e2 = new SAXException(e.getMessage());
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/RefPattern.java b/libjava/classpath/gnu/xml/validation/relaxng/RefPattern.java
new file mode 100644
index 000000000..8c1ff8539
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/RefPattern.java
@@ -0,0 +1,51 @@
+/* RefPattern.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG ref element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class RefPattern
+ extends Pattern
+{
+
+ String name;
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/TextPattern.java b/libjava/classpath/gnu/xml/validation/relaxng/TextPattern.java
new file mode 100644
index 000000000..81c502820
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/TextPattern.java
@@ -0,0 +1,51 @@
+/* TextPattern.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+/**
+ * A RELAX NG text element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class TextPattern
+ extends Pattern
+{
+
+ static final TextPattern INSTANCE = new TextPattern();
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/relaxng/ValuePattern.java b/libjava/classpath/gnu/xml/validation/relaxng/ValuePattern.java
new file mode 100644
index 000000000..8b63d79ae
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/relaxng/ValuePattern.java
@@ -0,0 +1,57 @@
+/* ValuePattern.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.relaxng;
+
+import org.relaxng.datatype.Datatype;
+import org.relaxng.datatype.DatatypeLibrary;
+
+/**
+ * A RELAX NG value element.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class ValuePattern
+ extends Pattern
+{
+
+ DatatypeLibrary datatypeLibrary;
+ Datatype type;
+ String ns;
+ String value;
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/AnyAttribute.java b/libjava/classpath/gnu/xml/validation/xmlschema/AnyAttribute.java
new file mode 100644
index 000000000..6f94bfe28
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/AnyAttribute.java
@@ -0,0 +1,66 @@
+/* AnyAttribute.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+import gnu.xml.validation.datatype.Annotation;
+
+/**
+ * An attribute wildcard.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class AnyAttribute
+{
+
+ static final int STRICT = 0;
+ static final int LAX = 1;
+ static final int SKIP = 2;
+
+ final String namespace;
+
+ final int processContents;
+
+ Annotation annotation;
+
+ AnyAttribute(String namespace, int processContents)
+ {
+ this.namespace = namespace;
+ this.processContents = processContents;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/AttributeDeclaration.java b/libjava/classpath/gnu/xml/validation/xmlschema/AttributeDeclaration.java
new file mode 100644
index 000000000..c475b368d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/AttributeDeclaration.java
@@ -0,0 +1,98 @@
+/* AttributeDeclaration.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+import gnu.xml.validation.datatype.Annotation;
+import gnu.xml.validation.datatype.SimpleType;
+import javax.xml.namespace.QName;
+
+/**
+ * An XML Schema attribute declaration schema component.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class AttributeDeclaration
+{
+
+ static final int NONE = 0;
+ static final int DEFAULT = 1;
+ static final int FIXED = 2;
+
+ /**
+ * The scope of this attribute declaration (global or local).
+ */
+ final boolean scope;
+
+ /**
+ * The constraint type.
+ * One of NONE, DEFAULT, FIXED.
+ */
+ final int type;
+
+ /**
+ * The value constraint.
+ */
+ final String value;
+
+ /**
+ * The name of the attribute to which this declaration refers.
+ */
+ final QName name;
+
+ /**
+ * The type definition corresponding to this attribute.
+ */
+ final SimpleType datatype;
+
+ /**
+ * The annotation associated with this attribute declaration, if any.
+ */
+ final Annotation annotation;
+
+ AttributeDeclaration(boolean scope, int type, String value, QName name,
+ SimpleType datatype, Annotation annotation)
+ {
+ this.scope = scope;
+ this.type = type;
+ this.value = value;
+ this.name = name;
+ this.datatype = datatype;
+ this.annotation = annotation;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/AttributeUse.java b/libjava/classpath/gnu/xml/validation/xmlschema/AttributeUse.java
new file mode 100644
index 000000000..937076338
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/AttributeUse.java
@@ -0,0 +1,78 @@
+/* AttributeUse.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+/**
+ * An XML Schema attribute use schema component.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class AttributeUse
+{
+
+ /**
+ * Whether the attribute is required.
+ */
+ final boolean required;
+
+ /**
+ * The constraint type.
+ * One of NONE, DEFAULT, FIXED.
+ */
+ final int type;
+
+ /**
+ * The value constraint.
+ */
+ final String value;
+
+ /**
+ * The name of the attribute to which this declaration refers.
+ */
+ final AttributeDeclaration declaration;
+
+ AttributeUse(boolean required, int type, String value,
+ AttributeDeclaration declaration)
+ {
+ this.required = required;
+ this.type = type;
+ this.value = value;
+ this.declaration = declaration;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/ComplexType.java b/libjava/classpath/gnu/xml/validation/xmlschema/ComplexType.java
new file mode 100644
index 000000000..826ba32d9
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/ComplexType.java
@@ -0,0 +1,101 @@
+/* ComplexType.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+import javax.xml.namespace.QName;
+import gnu.xml.validation.datatype.Type;
+
+/**
+ * A complex type definition.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class ComplexType
+ extends Type
+{
+
+ /**
+ * Either a simple type definition or a complex type definition.
+ */
+ QName baseType;
+
+ /**
+ * Either EXTENSION or RESTRICTION.
+ */
+ int derivationMethod;
+
+ /**
+ * A subset of {EXTENSION, RESTRICTION}.
+ */
+ final int finality;
+
+ final boolean isAbstract;
+
+ Set attributeUses;
+
+ AnyAttribute attributeWildcard;
+
+ /**
+ * One of EMPTY, SIMPLE, MIXED, or ELEMENT_ONLY.
+ */
+ int contentType;
+
+ /**
+ * A simple type definition or a Particle.
+ */
+ Object contentModel;
+
+ final int prohibitedSubstitutions;
+
+ Set annotations;
+
+ ComplexType(QName name,
+ boolean isAbstract,
+ int prohibitedSubstitutions,
+ int finality)
+ {
+ super(name);
+ this.isAbstract = isAbstract;
+ this.prohibitedSubstitutions = prohibitedSubstitutions;
+ this.finality = finality;
+ attributeUses = new LinkedHashSet();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/ElementDeclaration.java b/libjava/classpath/gnu/xml/validation/xmlschema/ElementDeclaration.java
new file mode 100644
index 000000000..7392ca596
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/ElementDeclaration.java
@@ -0,0 +1,124 @@
+/* ElementDeclaration.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+import gnu.xml.validation.datatype.Annotation;
+import gnu.xml.validation.datatype.Type;
+import javax.xml.namespace.QName;
+
+/**
+ * An XML Schema element declaration schema component.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class ElementDeclaration
+{
+
+ /**
+ * The name of the element to which this declaration refers.
+ */
+ final QName name;
+
+ /**
+ * The type definition corresponding to this element.
+ */
+ Type datatype;
+
+ /**
+ * The scope of this schema component.
+ * One of GLOBAL, LOCAL, or ABSENT.
+ */
+ final int scope;
+
+ /**
+ * If scope is LOCAL, the parent element definition.
+ */
+ final ElementDeclaration parent;
+
+ /**
+ * The constraint type.
+ * One of NONE, DEFAULT, FIXED.
+ */
+ final int type;
+
+ /**
+ * The value constraint.
+ */
+ final String value;
+
+ final boolean nillable;
+
+ // TODO identity-constraint definitions
+
+ final QName substitutionGroup;
+
+ final int substitutionGroupExclusions;
+
+ final int disallowedSubstitutions;
+
+ final boolean isAbstract;
+
+ /**
+ * The annotation associated with this attribute declaration, if any.
+ */
+ Annotation annotation;
+
+ ElementDeclaration(QName name,
+ Type datatype,
+ int scope, ElementDeclaration parent,
+ int type, String value,
+ boolean nillable,
+ QName substitutionGroup,
+ int substitutionGroupExclusions,
+ int disallowedSubstitutions,
+ boolean isAbstract)
+ {
+ this.name = name;
+ this.datatype = datatype;
+ this.scope = scope;
+ this.parent = parent;
+ this.type = type;
+ this.value = value;
+ this.nillable = nillable;
+ this.substitutionGroup = substitutionGroup;
+ this.substitutionGroupExclusions = substitutionGroupExclusions;
+ this.disallowedSubstitutions = disallowedSubstitutions;
+ this.isAbstract = isAbstract;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/Particle.java b/libjava/classpath/gnu/xml/validation/xmlschema/Particle.java
new file mode 100644
index 000000000..5fe49203e
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/Particle.java
@@ -0,0 +1,60 @@
+/* Particle.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+/**
+ * Container for element content.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class Particle
+{
+
+ final Integer minOccurs;
+ final Integer maxOccurs;
+
+ final Object term;
+
+ Particle(Integer minOccurs, Integer maxOccurs, Object term)
+ {
+ this.minOccurs = minOccurs;
+ this.maxOccurs = maxOccurs;
+ this.term = term;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/ValidationException.java b/libjava/classpath/gnu/xml/validation/xmlschema/ValidationException.java
new file mode 100644
index 000000000..716ba8800
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/ValidationException.java
@@ -0,0 +1,57 @@
+/* ValidationException.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+import org.xml.sax.Locator;
+import org.xml.sax.SAXParseException;
+
+/**
+ * An XML Schema validation rule violation.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class ValidationException
+ extends SAXParseException
+{
+
+ ValidationException(String message, Locator locator)
+ {
+ super(message, locator);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchema.java b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchema.java
new file mode 100644
index 000000000..fb8eb88b1
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchema.java
@@ -0,0 +1,133 @@
+/* XMLSchema.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+import javax.xml.validation.Schema;
+import javax.xml.validation.Validator;
+import javax.xml.validation.ValidatorHandler;
+
+/**
+ * An XML Schema schema.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class XMLSchema
+ extends Schema
+{
+
+ static final int FINAL_NONE = 0x00;
+ static final int FINAL_EXTENSION = 0x01;
+ static final int FINAL_RESTRICTION = 0x02;
+ static final int FINAL_LIST = 0x04;
+ static final int FINAL_UNION = 0x08;
+ static final int FINAL_ALL = 0x0f;
+
+ static final int BLOCK_NONE = 0x00;
+ static final int BLOCK_EXTENSION = 0x01;
+ static final int BLOCK_RESTRICTION = 0x02;
+ static final int BLOCK_SUBSTITUTION = 0x04;
+ static final int BLOCK_ALL = 0x07;
+
+ static final int GLOBAL = 0x00;
+ static final int LOCAL = 0x01;
+ static final int ABSENT = 0x02;
+
+ static final int CONSTRAINT_NONE = 0x00;
+ static final int CONSTRAINT_DEFAULT = 0x01;
+ static final int CONSTRAINT_FIXED = 0x02;
+
+ static final int CONTENT_EMPTY = 0x00;
+ static final int CONTENT_SIMPLE = 0x01;
+ static final int CONTENT_MIXED = 0x02;
+ static final int CONTENT_ELEMENT_ONLY = 0x03;
+
+ final String targetNamespace;
+ final String version;
+ final int finalDefault;
+ final int blockDefault;
+ final boolean attributeFormQualified;
+ final boolean elementFormQualified;
+
+ /**
+ * The element declarations in this schema.
+ */
+ final Map elementDeclarations;
+
+ /**
+ * The attribute declarations in this schema.
+ */
+ final Map attributeDeclarations;
+
+ /**
+ * The type declarations in this schema.
+ */
+ final Map types;
+
+ XMLSchema(String targetNamespace, String version,
+ int finalDefault, int blockDefault,
+ boolean attributeFormQualified,
+ boolean elementFormQualified)
+ {
+ this.targetNamespace = targetNamespace;
+ this.version = version;
+ this.finalDefault = finalDefault;
+ this.blockDefault = blockDefault;
+ this.attributeFormQualified = attributeFormQualified;
+ this.elementFormQualified = elementFormQualified;
+ elementDeclarations = new LinkedHashMap();
+ attributeDeclarations = new LinkedHashMap();
+ types = new LinkedHashMap();
+ }
+
+ public Validator newValidator()
+ {
+ // TODO
+ //return new XMLSchemaValidator(this);
+ return null;
+ }
+
+ public ValidatorHandler newValidatorHandler()
+ {
+ // TODO
+ //return new XMLSchemaValidatorHandler(this);
+ return null;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaAttributeTypeInfo.java b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaAttributeTypeInfo.java
new file mode 100644
index 000000000..ba83973df
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaAttributeTypeInfo.java
@@ -0,0 +1,98 @@
+/* XMLSchemaAttributeTypeInfo.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+import gnu.xml.validation.datatype.SimpleType;
+
+/**
+ * Attribute type information provided by validation against an XML Schema.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class XMLSchemaAttributeTypeInfo
+ extends XMLSchemaTypeInfo
+{
+
+ final XMLSchema schema;
+ final AttributeDeclaration decl;
+ final SimpleType type;
+ boolean id;
+ final boolean specified;
+
+ XMLSchemaAttributeTypeInfo(XMLSchema schema, AttributeDeclaration decl,
+ boolean specified)
+ {
+ this.schema = schema;
+ this.decl = decl;
+ this.specified = specified;
+ type = (decl == null) ? null : decl.datatype;
+ }
+
+ public String getTypeName()
+ {
+ if (type == null)
+ {
+ return "CDATA";
+ }
+ return type.name.getLocalPart();
+ }
+
+ public String getTypeNamespace()
+ {
+ if (type == null)
+ {
+ return "";
+ }
+ return type.name.getNamespaceURI();
+ }
+
+ public boolean isDerivedFrom(String typeNamespace, String typeName,
+ int derivationMethod)
+ {
+ if (type == null)
+ {
+ return false;
+ }
+ else
+ {
+ return simpleTypeIsDerivedFrom(type, typeNamespace, typeName,
+ derivationMethod);
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaBuilder.java b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaBuilder.java
new file mode 100644
index 000000000..a7bad3129
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaBuilder.java
@@ -0,0 +1,839 @@
+/* XMLSchemaBuilder.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+import java.util.LinkedHashSet;
+import java.util.Set;
+import java.util.StringTokenizer;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.DatatypeLibrary;
+import org.relaxng.datatype.helpers.DatatypeLibraryLoader;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+import gnu.xml.validation.datatype.Annotation;
+import gnu.xml.validation.datatype.SimpleType;
+import gnu.xml.validation.datatype.Type;
+
+/**
+ * Parses an XML Schema DOM tree, constructing a compiled internal
+ * representation.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class XMLSchemaBuilder
+{
+
+ XMLSchema schema;
+ final DatatypeLibrary typeLibrary;
+
+ XMLSchemaBuilder()
+ {
+ final String ns = XMLConstants.W3C_XML_SCHEMA_NS_URI;
+ typeLibrary = new DatatypeLibraryLoader().createDatatypeLibrary(ns);
+ }
+
+ void parseSchema(Node node)
+ throws DatatypeException
+ {
+ String uri = node.getNamespaceURI();
+ String name = node.getLocalName();
+ if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
+ node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ if ("schema".equals(name))
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String targetNamespace = getAttribute(attrs, "targetNamespace");
+ String version = getAttribute(attrs, "version");
+ String fd = getAttribute(attrs, "finalDefault");
+ int finalDefault = parseFullDerivationSet(fd);
+ String bd = getAttribute(attrs, "blockDefault");
+ int blockDefault = parseBlockSet(bd);
+ String afd = getAttribute(attrs, "attributeFormDefault");
+ boolean attributeFormQualified = "qualified".equals(afd);
+ String efd = getAttribute(attrs, "elementFormDefault");
+ boolean elementFormQualified = "qualified".equals(efd);
+ schema = new XMLSchema(targetNamespace, version,
+ finalDefault, blockDefault,
+ attributeFormQualified,
+ elementFormQualified);
+ for (Node child = node.getFirstChild(); child != null;
+ child = child.getNextSibling())
+ {
+ parseTopLevelElement(child);
+ }
+ return;
+ }
+ }
+ // TODO throw schema exception
+ }
+
+ void parseTopLevelElement(Node node)
+ throws DatatypeException
+ {
+ String uri = node.getNamespaceURI();
+ String name = node.getLocalName();
+ if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
+ node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ if ("element".equals(name))
+ {
+ ElementDeclaration ed =
+ (ElementDeclaration) parseElement(node, null);
+ schema.elementDeclarations.put(ed.name, ed);
+ // TODO
+ }
+ else if ("attribute".equals(name))
+ {
+ AttributeDeclaration ad =
+ (AttributeDeclaration) parseAttribute(node, true);
+ schema.attributeDeclarations.put(ad.name, ad);
+ // TODO
+ }
+ else if ("type".equals(name))
+ {
+ // TODO
+ }
+ else if ("group".equals(name))
+ {
+ // TODO
+ }
+ else if ("attributeGroup".equals(name))
+ {
+ // TODO
+ }
+ else if ("notation".equals(name))
+ {
+ // TODO
+ }
+ else if ("identityConstraint".equals(name))
+ {
+ // TODO
+ }
+ }
+ // TODO throw schema exception
+ }
+
+ Object parseAttribute(Node node, boolean scope)
+ throws DatatypeException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String def = getAttribute(attrs, "default");
+ String fixed = getAttribute(attrs, "fixed");
+ int constraintType = AttributeDeclaration.NONE;
+ String constraintValue = null;
+ if (def != null)
+ {
+ constraintType = AttributeDeclaration.DEFAULT;
+ constraintValue = def;
+ }
+ else if (fixed != null)
+ {
+ constraintType = AttributeDeclaration.FIXED;
+ constraintValue = fixed;
+ }
+ // TODO form = (qualified | unqualified)
+ String attrName = getAttribute(attrs, "name");
+ String attrNamespace = getAttribute(attrs, "targetNamespace");
+ String ref = getAttribute(attrs, "ref");
+ String use = getAttribute(attrs, "use");
+ String type = getAttribute(attrs, "type");
+ SimpleType datatype = (type == null) ? null :
+ parseSimpleType(asQName(type, node));
+ Annotation annotation = null;
+ for (Node child = node.getFirstChild(); child != null;
+ child = child.getNextSibling())
+ {
+ String uri = child.getNamespaceURI();
+ String name = child.getLocalName();
+ if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
+ child.getNodeType() == Node.ELEMENT_NODE)
+ {
+ if ("annotation".equals(name))
+ {
+ annotation = parseAnnotation(child);
+ }
+ else if ("simpleType".equals(name))
+ {
+ datatype = parseSimpleType(child);
+ }
+ else
+ {
+ // TODO throw schema exception
+ }
+ }
+ }
+ if (scope)
+ {
+ return new AttributeDeclaration(scope,
+ constraintType,
+ constraintValue,
+ new QName(attrNamespace, attrName),
+ datatype,
+ annotation);
+ }
+ else
+ {
+ boolean required = "required".equals(use);
+ // TODO ref
+ AttributeDeclaration decl = (ref == null) ?
+ new AttributeDeclaration(scope,
+ AttributeDeclaration.NONE,
+ null,
+ new QName(attrNamespace, attrName),
+ datatype,
+ annotation) :
+ /*schema.getAttributeDeclaration(ref)*/ null;
+ return new AttributeUse(required,
+ constraintType,
+ constraintValue,
+ decl);
+ }
+ }
+
+ int parseFullDerivationSet(String value)
+ {
+ int ret = XMLSchema.FINAL_NONE;
+ if ("#all".equals(value))
+ {
+ ret = XMLSchema.FINAL_ALL;
+ }
+ else
+ {
+ StringTokenizer st = new StringTokenizer(value, " ");
+ while (st.hasMoreTokens())
+ {
+ String token = st.nextToken();
+ if ("extension".equals(token))
+ {
+ ret |= XMLSchema.FINAL_EXTENSION;
+ }
+ else if ("restriction".equals(token))
+ {
+ ret |= XMLSchema.FINAL_RESTRICTION;
+ }
+ else if ("list".equals(token))
+ {
+ ret |= XMLSchema.FINAL_LIST;
+ }
+ else if ("union".equals(token))
+ {
+ ret |= XMLSchema.FINAL_UNION;
+ }
+ }
+ }
+ return ret;
+ }
+
+ int parseSimpleTypeDerivationSet(String value)
+ {
+ int ret = XMLSchema.FINAL_NONE;
+ if ("#all".equals(value))
+ {
+ ret = XMLSchema.FINAL_LIST |
+ XMLSchema.FINAL_UNION |
+ XMLSchema.FINAL_RESTRICTION;
+ }
+ else
+ {
+ StringTokenizer st = new StringTokenizer(value, " ");
+ while (st.hasMoreTokens())
+ {
+ String token = st.nextToken();
+ if ("list".equals(token))
+ {
+ ret |= XMLSchema.FINAL_LIST;
+ }
+ else if ("union".equals(token))
+ {
+ ret |= XMLSchema.FINAL_UNION;
+ }
+ else if ("restriction".equals(token))
+ {
+ ret |= XMLSchema.FINAL_RESTRICTION;
+ }
+ }
+ }
+ return ret;
+ }
+
+ int parseComplexTypeDerivationSet(String value)
+ {
+ int ret = XMLSchema.FINAL_NONE;
+ if ("#all".equals(value))
+ {
+ ret = XMLSchema.FINAL_EXTENSION | XMLSchema.FINAL_RESTRICTION;
+ }
+ else
+ {
+ StringTokenizer st = new StringTokenizer(value, " ");
+ while (st.hasMoreTokens())
+ {
+ String token = st.nextToken();
+ if ("extension".equals(token))
+ {
+ ret |= XMLSchema.FINAL_EXTENSION;
+ }
+ else if ("restriction".equals(token))
+ {
+ ret |= XMLSchema.FINAL_RESTRICTION;
+ }
+ }
+ }
+ return ret;
+ }
+
+ int parseBlockSet(String value)
+ {
+ int ret = XMLSchema.BLOCK_NONE;
+ if ("#all".equals(value))
+ {
+ ret = XMLSchema.BLOCK_ALL;
+ }
+ else
+ {
+ StringTokenizer st = new StringTokenizer(value, " ");
+ while (st.hasMoreTokens())
+ {
+ String token = st.nextToken();
+ if ("extension".equals(token))
+ {
+ ret |= XMLSchema.BLOCK_EXTENSION;
+ }
+ else if ("restriction".equals(token))
+ {
+ ret |= XMLSchema.BLOCK_RESTRICTION;
+ }
+ else if ("substitution".equals(token))
+ {
+ ret |= XMLSchema.BLOCK_SUBSTITUTION;
+ }
+ }
+ }
+ return ret;
+ }
+
+ int parseComplexTypeBlockSet(String value)
+ {
+ int ret = XMLSchema.BLOCK_NONE;
+ if ("#all".equals(value))
+ {
+ ret = XMLSchema.BLOCK_EXTENSION | XMLSchema.BLOCK_RESTRICTION;
+ }
+ else
+ {
+ StringTokenizer st = new StringTokenizer(value, " ");
+ while (st.hasMoreTokens())
+ {
+ String token = st.nextToken();
+ if ("extension".equals(token))
+ {
+ ret |= XMLSchema.BLOCK_EXTENSION;
+ }
+ else if ("restriction".equals(token))
+ {
+ ret |= XMLSchema.BLOCK_RESTRICTION;
+ }
+ }
+ }
+ return ret;
+ }
+
+ Object parseElement(Node node, ElementDeclaration parent)
+ throws DatatypeException
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ Integer minOccurs = null;
+ Integer maxOccurs = null;
+ Node parentNode = node.getParentNode();
+ boolean notTopLevel = !"schema".equals(parentNode.getLocalName());
+ if (notTopLevel)
+ {
+ String ref = getAttribute(attrs, "ref");
+ if (ref != null)
+ {
+ minOccurs = getOccurrence(getAttribute(attrs, "minOccurs"));
+ maxOccurs = getOccurrence(getAttribute(attrs, "maxOccurs"));
+ // TODO resolve top-level element declaration
+ ElementDeclaration ad = null;
+ return new Particle(minOccurs, maxOccurs, ad);
+ }
+ }
+ String elementName = getAttribute(attrs, "name");
+ String elementNamespace = getAttribute(attrs, "targetNamespace");
+ String type = getAttribute(attrs, "type");
+ Type datatype = (type != null) ?
+ parseSimpleType(asQName(type, node)) : null;
+ int scope = (parent == null) ?
+ XMLSchema.GLOBAL :
+ XMLSchema.LOCAL;
+ String def = getAttribute(attrs, "default");
+ String fixed = getAttribute(attrs, "fixed");
+ int constraintType = AttributeDeclaration.NONE;
+ String constraintValue = null;
+ if (def != null)
+ {
+ constraintType = AttributeDeclaration.DEFAULT;
+ constraintValue = def;
+ }
+ else if (fixed != null)
+ {
+ constraintType = AttributeDeclaration.FIXED;
+ constraintValue = fixed;
+ }
+ String sg = getAttribute(attrs, "substitutionGroup");
+ QName substitutionGroup = QName.valueOf(sg);
+ String sgPrefix = substitutionGroup.getPrefix();
+ if (sgPrefix != null && !"".equals(sgPrefix))
+ {
+ String sgName = substitutionGroup.getLocalPart();
+ String sgNamespace = node.lookupNamespaceURI(sgPrefix);
+ substitutionGroup = new QName(sgNamespace, sgName);
+ }
+
+ String block = getAttribute(attrs, "block");
+ int substitutionGroupExclusions = (block == null) ?
+ schema.blockDefault :
+ parseBlockSet(block);
+ String final_ = getAttribute(attrs, "final");
+ int disallowedSubstitutions = (final_ == null) ?
+ schema.finalDefault :
+ parseFullDerivationSet(final_);
+
+ boolean nillable = "true".equals(getAttribute(attrs, "nillable"));
+ boolean isAbstract = "true".equals(getAttribute(attrs, "abstract"));
+
+ if (notTopLevel)
+ {
+ minOccurs = getOccurrence(getAttribute(attrs, "minOccurs"));
+ maxOccurs = getOccurrence(getAttribute(attrs, "maxOccurs"));
+ String form = getAttribute(attrs, "form");
+ if (form != null)
+ {
+ if ("qualified".equals(form))
+ {
+ elementNamespace = schema.targetNamespace;
+ }
+ }
+ else if (schema.elementFormQualified)
+ {
+ elementNamespace = schema.targetNamespace;
+ }
+ }
+ ElementDeclaration ed =
+ new ElementDeclaration(new QName(elementNamespace, elementName),
+ datatype,
+ scope, parent,
+ constraintType, constraintValue,
+ nillable,
+ substitutionGroup,
+ substitutionGroupExclusions,
+ disallowedSubstitutions,
+ isAbstract);
+
+ for (Node child = node.getFirstChild(); child != null;
+ child = child.getNextSibling())
+ {
+ String uri = child.getNamespaceURI();
+ String name = child.getLocalName();
+ if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
+ child.getNodeType() == Node.ELEMENT_NODE)
+ {
+ if ("annotation".equals(name))
+ {
+ ed.annotation = parseAnnotation(child);
+ }
+ else if ("simpleType".equals(name) && datatype == null)
+ {
+ ed.datatype = parseSimpleType(child);
+ }
+ else if ("complexType".equals(name) && datatype == null)
+ {
+ ed.datatype = parseComplexType(child, ed);
+ }
+ else
+ {
+ // throw schema exception
+ }
+ }
+ }
+
+ if (notTopLevel)
+ {
+ return new Particle(minOccurs, maxOccurs, ed);
+ }
+ else
+ {
+ return ed;
+ }
+ }
+
+ Integer getOccurrence(String value)
+ {
+ if (value == null)
+ {
+ return new Integer(1);
+ }
+ else if ("unbounded".equals(value))
+ {
+ return null;
+ }
+ else
+ {
+ return new Integer(value);
+ }
+ }
+
+ SimpleType parseSimpleType(QName typeName)
+ throws DatatypeException
+ {
+ SimpleType type = (SimpleType) schema.types.get(typeName);
+ if (!XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(typeName.getNamespaceURI()))
+ return null;
+ String localName = typeName.getLocalPart();
+ return (SimpleType) typeLibrary.createDatatype(localName);
+ }
+
+ SimpleType parseSimpleType(Node simpleType)
+ throws DatatypeException
+ {
+ NamedNodeMap attrs = simpleType.getAttributes();
+ String typeFinal = getAttribute(attrs, "final");
+ if (typeFinal == null)
+ {
+ Node schema = simpleType.getParentNode();
+ while (schema != null && !"schema".equals(schema.getLocalName()))
+ {
+ schema = schema.getParentNode();
+ }
+ if (schema != null)
+ {
+ NamedNodeMap schemaAttrs = schema.getAttributes();
+ typeFinal = getAttribute(schemaAttrs, "finalDefault");
+ }
+ }
+ int typeFinality = parseSimpleTypeDerivationSet(typeFinal);
+ QName typeName = asQName(getAttribute(attrs, "name"), simpleType);
+ int variety = 0;
+ Set facets = new LinkedHashSet();
+ int fundamentalFacets = 0; // TODO
+ SimpleType baseType = null; // TODO
+ Annotation annotation = null;
+ // TODO use DatatypeBuilder
+ for (Node child = simpleType.getFirstChild(); child != null;
+ child = child.getNextSibling())
+ {
+ String uri = child.getNamespaceURI();
+ String name = child.getLocalName();
+ if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
+ child.getNodeType() == Node.ELEMENT_NODE)
+ {
+ if ("annotation".equals(name))
+ {
+ annotation = parseAnnotation(child);
+ }
+ else if ("restriction".equals(name))
+ {
+ // TODO
+ }
+ else if ("list".equals(name))
+ {
+ variety = SimpleType.LIST;
+ // TODO
+ }
+ else if ("union".equals(name))
+ {
+ variety = SimpleType.UNION;
+ // TODO
+ }
+ }
+ }
+ return new SimpleType(typeName, variety, facets, fundamentalFacets,
+ baseType, annotation);
+ }
+
+ Type parseComplexType(Node complexType, ElementDeclaration parent)
+ throws DatatypeException
+ {
+ NamedNodeMap attrs = complexType.getAttributes();
+ QName typeName = asQName(getAttribute(attrs, "name"), complexType);
+ boolean isAbstract = "true".equals(getAttribute(attrs, "abstract"));
+ String block = getAttribute(attrs, "block");
+ int prohibitedSubstitutions = (block == null) ?
+ schema.blockDefault :
+ parseComplexTypeBlockSet(block);
+ String final_ = getAttribute(attrs, "final");
+ int finality = (final_ == null) ?
+ schema.finalDefault :
+ parseComplexTypeDerivationSet(final_);
+ ComplexType type = new ComplexType(typeName, isAbstract,
+ prohibitedSubstitutions, finality);
+ boolean mixed = "true".equals(getAttribute(attrs, "mixed"));
+ for (Node child = complexType.getFirstChild(); child != null;
+ child = child.getNextSibling())
+ {
+ String uri = child.getNamespaceURI();
+ String name = child.getLocalName();
+ if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
+ child.getNodeType() == Node.ELEMENT_NODE)
+ {
+ if ("simpleContent".equals(name))
+ {
+ parseSimpleContent(child, type);
+ }
+ }
+ }
+ if (mixed)
+ {
+ type.contentType = XMLSchema.CONTENT_MIXED;
+ }
+ return type;
+ }
+
+ void parseSimpleContent(Node simpleContent, ComplexType type)
+ throws DatatypeException
+ {
+ for (Node child = simpleContent.getFirstChild(); child != null;
+ child = child.getNextSibling())
+ {
+ String uri = child.getNamespaceURI();
+ String name = child.getLocalName();
+ if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
+ child.getNodeType() == Node.ELEMENT_NODE)
+ {
+ if ("annotation".equals(name))
+ {
+ type.annotations.add(parseAnnotation(child));
+ }
+ else if ("restriction".equals(name))
+ {
+ type.derivationMethod = XMLSchema.FINAL_RESTRICTION;
+ parseRestriction(child, type);
+ }
+ else if ("extension".equals(name))
+ {
+ type.derivationMethod = XMLSchema.FINAL_EXTENSION;
+ parseExtension(child, type);
+ }
+ }
+ }
+ }
+
+ void parseRestriction(Node restriction, ComplexType type)
+ throws DatatypeException
+ {
+ NamedNodeMap attrs = restriction.getAttributes();
+ String base = getAttribute(attrs, "base");
+ QName baseType = asQName(base, restriction);
+ SimpleType simpleType = null;
+ for (Node child = restriction.getFirstChild(); child != null;
+ child = child.getNextSibling())
+ {
+ String uri = child.getNamespaceURI();
+ String name = child.getLocalName();
+ if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
+ child.getNodeType() == Node.ELEMENT_NODE)
+ {
+ if ("annotation".equals(name))
+ {
+ type.annotations.add(parseAnnotation(child));
+ }
+ else if ("simpleType".equals(name))
+ {
+ type.contentType = XMLSchema.CONTENT_SIMPLE;
+ simpleType = parseSimpleType(child);
+ }
+ else if ("minExclusive".equals(name))
+ {
+ }
+ else if ("minInclusive".equals(name))
+ {
+ }
+ else if ("maxExclusive".equals(name))
+ {
+ }
+ else if ("maxInclusive".equals(name))
+ {
+ }
+ else if ("totalDigits".equals(name))
+ {
+ }
+ else if ("fractionDigits".equals(name))
+ {
+ }
+ else if ("length".equals(name))
+ {
+ }
+ else if ("minLength".equals(name))
+ {
+ }
+ else if ("maxLength".equals(name))
+ {
+ }
+ else if ("enumeration".equals(name))
+ {
+ }
+ else if ("whiteSpace".equals(name))
+ {
+ }
+ else if ("pattern".equals(name))
+ {
+ }
+ else if ("attribute".equals(name))
+ {
+ AttributeUse use =
+ (AttributeUse) parseAttribute(child, false);
+ schema.attributeDeclarations.put(use.declaration.name,
+ use.declaration);
+ type.attributeUses.add(use);
+ }
+ else if ("attributeGroup".equals(name))
+ {
+ NamedNodeMap agAttrs = child.getAttributes();
+ String ref = getAttribute(agAttrs, "ref");
+ QName ag = asQName(ref, child);
+ type.attributeUses.add(ag);
+ }
+ else if ("anyAttribute".equals(name))
+ {
+ type.attributeWildcard = parseAnyAttribute(child);
+ }
+ }
+ }
+ }
+
+ void parseExtension(Node extension, ComplexType type)
+ throws DatatypeException
+ {
+ NamedNodeMap attrs = extension.getAttributes();
+ String base = getAttribute(attrs, "base");
+ QName baseType = asQName(base, extension);
+ for (Node child = extension.getFirstChild(); child != null;
+ child = child.getNextSibling())
+ {
+ String uri = child.getNamespaceURI();
+ String name = child.getLocalName();
+ if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
+ child.getNodeType() == Node.ELEMENT_NODE)
+ {
+ if ("annotation".equals(name))
+ {
+ type.annotations.add(parseAnnotation(child));
+ }
+ else if ("attribute".equals(name))
+ {
+ AttributeUse use =
+ (AttributeUse) parseAttribute(child, false);
+ schema.attributeDeclarations.put(use.declaration.name,
+ use.declaration);
+ type.attributeUses.add(use);
+ }
+ else if ("attributeGroup".equals(name))
+ {
+ NamedNodeMap agAttrs = child.getAttributes();
+ String ref = getAttribute(agAttrs, "ref");
+ QName ag = asQName(ref, child);
+ type.attributeUses.add(ag);
+ }
+ else if ("anyAttribute".equals(name))
+ {
+ type.attributeWildcard = parseAnyAttribute(child);
+ }
+ }
+ }
+ }
+
+ AnyAttribute parseAnyAttribute(Node node)
+ {
+ NamedNodeMap attrs = node.getAttributes();
+ String namespace = getAttribute(attrs, "namespace");
+ String pc = getAttribute(attrs, "processContents");
+ int processContents = AnyAttribute.STRICT;
+ if ("lax".equals(pc))
+ {
+ processContents = AnyAttribute.LAX;
+ }
+ else if ("skip".equals(pc))
+ {
+ processContents = AnyAttribute.SKIP;
+ }
+ AnyAttribute ret = new AnyAttribute(namespace, processContents);
+ for (Node child = node.getFirstChild(); child != null;
+ child = child.getNextSibling())
+ {
+ String uri = child.getNamespaceURI();
+ String name = child.getLocalName();
+ if (XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri) &&
+ child.getNodeType() == Node.ELEMENT_NODE)
+ {
+ if ("annotation".equals(name))
+ {
+ ret.annotation = parseAnnotation(child);
+ }
+ }
+ }
+ return ret;
+ }
+
+ Annotation parseAnnotation(Node node)
+ {
+ // TODO
+ return null;
+ }
+
+ private static String getAttribute(NamedNodeMap attrs, String name)
+ {
+ Node attr = attrs.getNamedItem(name);
+ return (attr == null) ? null : attr.getNodeValue();
+ }
+
+ private static QName asQName(String text, Node resolver)
+ {
+ QName name = QName.valueOf(text);
+ String prefix = name.getPrefix();
+ if (prefix != null && prefix.length() > 0)
+ {
+ String uri = resolver.lookupNamespaceURI(prefix);
+ name = new QName(uri, name.getLocalPart());
+ }
+ return name;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaElementTypeInfo.java b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaElementTypeInfo.java
new file mode 100644
index 000000000..99a59f39d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaElementTypeInfo.java
@@ -0,0 +1,91 @@
+/* XMLSchemaElementTypeInfo.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+import gnu.xml.validation.datatype.SimpleType;
+import gnu.xml.validation.datatype.Type;
+
+/**
+ * Element type information provided by validation against an XML Schema.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class XMLSchemaElementTypeInfo
+ extends XMLSchemaTypeInfo
+{
+
+ final XMLSchema schema;
+ final ElementDeclaration decl;
+ final Type type;
+ boolean nil;
+
+ XMLSchemaElementTypeInfo(XMLSchema schema, ElementDeclaration decl,
+ Type type)
+ {
+ this.schema = schema;
+ this.decl = decl;
+ this.type = type;
+ }
+
+ public String getTypeName()
+ {
+ return type.name.getLocalPart();
+ }
+
+ public String getTypeNamespace()
+ {
+ return type.name.getNamespaceURI();
+ }
+
+ public boolean isDerivedFrom(String typeNamespace, String typeName,
+ int derivationMethod)
+ {
+ if (type instanceof SimpleType)
+ {
+ SimpleType simpleType = (SimpleType) type;
+ return simpleTypeIsDerivedFrom(simpleType, typeNamespace, typeName,
+ derivationMethod);
+ }
+ else
+ {
+ // TODO
+ return false;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaSchemaFactory.java b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaSchemaFactory.java
new file mode 100644
index 000000000..18e91f28d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaSchemaFactory.java
@@ -0,0 +1,171 @@
+/* XMLSchemaSchemaFactory.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+import java.io.IOException;
+import java.net.URL;
+import javax.xml.XMLConstants;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.transform.Source;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.validation.Schema;
+import javax.xml.validation.SchemaFactory;
+import org.relaxng.datatype.DatatypeException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.ls.LSResourceResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * Schema factory for W3C XML Schema schemata.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class XMLSchemaSchemaFactory
+ extends SchemaFactory
+{
+
+ LSResourceResolver resourceResolver;
+ ErrorHandler errorHandler;
+
+ public LSResourceResolver getResourceResolver()
+ {
+ return resourceResolver;
+ }
+
+ public void setResourceResolver(LSResourceResolver resourceResolver)
+ {
+ this.resourceResolver = resourceResolver;
+ }
+
+ public ErrorHandler getErrorHandler()
+ {
+ return this.errorHandler;
+ }
+
+ public void setErrorHandler(ErrorHandler errorHandler)
+ {
+ this.errorHandler = errorHandler;
+ }
+
+
+ public boolean isSchemaLanguageSupported(String schemaLanguage)
+ {
+ return XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(schemaLanguage);
+ }
+
+ public Schema newSchema()
+ throws SAXException
+ {
+ // TODO
+ throw new UnsupportedOperationException();
+ }
+
+ public Schema newSchema(Source[] schemata)
+ throws SAXException
+ {
+ if (schemata == null || schemata.length != 1)
+ throw new IllegalArgumentException("must specify one source");
+ // TODO multiple sources
+ try
+ {
+ Document doc = getDocument(schemata[0]);
+ XMLSchemaBuilder builder = new XMLSchemaBuilder();
+ builder.parseSchema(doc);
+ return builder.schema;
+ }
+ catch (IOException e)
+ {
+ SAXException e2 = new SAXException(e.getMessage());
+ e2.initCause(e);
+ throw e2;
+ }
+ catch (DatatypeException e)
+ {
+ SAXException e2 = new SAXException(e.getMessage());
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+ private static Document getDocument(Source source)
+ throws SAXException, IOException
+ {
+ if (source instanceof DOMSource)
+ {
+ Node node = ((DOMSource) source).getNode();
+ if (node != null && node instanceof Document)
+ return (Document) node;
+ }
+ String url = source.getSystemId();
+ try
+ {
+ InputSource input = new InputSource(url);
+ if (source instanceof StreamSource)
+ {
+ StreamSource streamSource = (StreamSource) source;
+ input.setByteStream(streamSource.getInputStream());
+ input.setCharacterStream(streamSource.getReader());
+ }
+ if (input.getByteStream() == null &&
+ input.getCharacterStream() == null &&
+ url != null)
+ input.setByteStream(new URL(url).openStream());
+ DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
+ f.setNamespaceAware(true);
+ f.setCoalescing(true);
+ f.setExpandEntityReferences(true);
+ f.setIgnoringComments(true);
+ f.setIgnoringElementContentWhitespace(true);
+ DocumentBuilder b = f.newDocumentBuilder();
+ return b.parse(input);
+ }
+ catch (ParserConfigurationException e)
+ {
+ SAXException e2 = new SAXException(e.getMessage());
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaTypeInfo.java b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaTypeInfo.java
new file mode 100644
index 000000000..c1ca95114
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaTypeInfo.java
@@ -0,0 +1,76 @@
+/* XMLSchemaTypeInfo.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+import org.w3c.dom.TypeInfo;
+import gnu.xml.validation.datatype.SimpleType;
+
+/**
+ * Abstract superclass providing simple type derivation.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+abstract class XMLSchemaTypeInfo
+ implements TypeInfo
+{
+
+ protected boolean simpleTypeIsDerivedFrom(SimpleType simpleType,
+ String typeNamespace,
+ String typeName,
+ int derivationMethod)
+ {
+ switch (derivationMethod)
+ {
+ case TypeInfo.DERIVATION_RESTRICTION:
+ SimpleType baseType = simpleType.baseType;
+ while (baseType != null)
+ {
+ if (baseType.name.getNamespaceURI().equals(typeNamespace) &&
+ baseType.name.getLocalPart().equals(typeName))
+ {
+ return true;
+ }
+ baseType = baseType.baseType;
+ }
+ break;
+ // TODO other methods
+ }
+ return false;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaTypeInfoProvider.java b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaTypeInfoProvider.java
new file mode 100644
index 000000000..4fc80d34b
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaTypeInfoProvider.java
@@ -0,0 +1,81 @@
+/* XMLSchemaTypeInfoProvider.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+import javax.xml.validation.TypeInfoProvider;
+import org.w3c.dom.TypeInfo;
+
+/**
+ * TypeInfo provider for XML Schema validator handler.
+ * This simply delegates to the handler. It wouldn't be required if
+ * TypeInfoProvider were an interface instead of an abstract class.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class XMLSchemaTypeInfoProvider
+ extends TypeInfoProvider
+{
+
+ final XMLSchemaValidatorHandler handler;
+
+ XMLSchemaTypeInfoProvider(XMLSchemaValidatorHandler handler)
+ {
+ this.handler = handler;
+ }
+
+ public TypeInfo getElementTypeInfo()
+ {
+ return handler.getElementTypeInfo();
+ }
+
+ public TypeInfo getAttributeTypeInfo(int index)
+ {
+ return handler.getAttributeTypeInfo(index);
+ }
+
+ public boolean isIdAttribute(int index)
+ {
+ return handler.isIdAttribute(index);
+ }
+
+ public boolean isSpecified(int index)
+ {
+ return handler.isSpecified(index);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaValidator.java b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaValidator.java
new file mode 100644
index 000000000..6239ba6c6
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaValidator.java
@@ -0,0 +1,97 @@
+/* XMLSchemaValidator.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+import java.io.IOException;
+import javax.xml.validation.Validator;
+import javax.xml.transform.Result;
+import javax.xml.transform.Source;
+import org.w3c.dom.ls.LSResourceResolver;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.SAXException;
+
+/**
+ * JAXP validator for an XML Schema.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class XMLSchemaValidator
+ extends Validator
+{
+
+ final XMLSchema schema;
+
+ ErrorHandler errorHandler;
+ LSResourceResolver resourceResolver;
+
+ XMLSchemaValidator(XMLSchema schema)
+ {
+ this.schema = schema;
+ }
+
+ public void reset()
+ {
+ }
+
+ public void validate(Source source, Result result)
+ throws SAXException, IOException
+ {
+ // TODO
+ }
+
+ public ErrorHandler getErrorHandler()
+ {
+ return errorHandler;
+ }
+
+ public void setErrorHandler(ErrorHandler errorHandler)
+ {
+ this.errorHandler = errorHandler;
+ }
+
+ public LSResourceResolver getResourceResolver()
+ {
+ return resourceResolver;
+ }
+
+ public void setResourceResolver(LSResourceResolver resourceResolver)
+ {
+ this.resourceResolver = resourceResolver;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaValidatorHandler.java b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaValidatorHandler.java
new file mode 100644
index 000000000..6c4f1f392
--- /dev/null
+++ b/libjava/classpath/gnu/xml/validation/xmlschema/XMLSchemaValidatorHandler.java
@@ -0,0 +1,393 @@
+/* XMLSchemaValidatorHandler.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.xml.validation.xmlschema;
+
+import java.util.ArrayList;
+import java.util.LinkedList;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import javax.xml.validation.TypeInfoProvider;
+import javax.xml.validation.ValidatorHandler;
+import org.relaxng.datatype.DatatypeException;
+import org.relaxng.datatype.DatatypeLibrary;
+import org.relaxng.datatype.helpers.DatatypeLibraryLoader;
+import org.w3c.dom.TypeInfo;
+import org.w3c.dom.ls.LSResourceResolver;
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.ErrorHandler;
+import org.xml.sax.Locator;
+import org.xml.sax.SAXException;
+import org.xml.sax.ext.Attributes2Impl;
+import org.xml.sax.helpers.NamespaceSupport;
+import gnu.xml.validation.datatype.SimpleType;
+import gnu.xml.validation.datatype.Type;
+
+/**
+ * Streaming validator.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class XMLSchemaValidatorHandler
+ extends ValidatorHandler
+{
+
+ final XMLSchema schema;
+ final TypeInfoProvider typeInfoProvider;
+ final NamespaceSupport namespaceSupport;
+ final DatatypeLibrary typeLibrary;
+ Locator loc;
+ ContentHandler contentHandler;
+ ErrorHandler errorHandler;
+ LSResourceResolver resourceResolver;
+ final LinkedList context; // element context
+ final ArrayList attributes; // attribute context;
+
+ XMLSchemaValidatorHandler(XMLSchema schema)
+ {
+ this.schema = schema;
+ typeInfoProvider = new XMLSchemaTypeInfoProvider(this);
+ namespaceSupport = new NamespaceSupport();
+ context = new LinkedList();
+ attributes = new ArrayList();
+ final String ns = XMLConstants.W3C_XML_SCHEMA_NS_URI;
+ typeLibrary = new DatatypeLibraryLoader().createDatatypeLibrary(ns);
+ }
+
+ public ContentHandler getContentHandler()
+ {
+ return contentHandler;
+ }
+
+ public void setContentHandler(ContentHandler contentHandler)
+ {
+ this.contentHandler = contentHandler;
+ }
+
+ public ErrorHandler getErrorHandler()
+ {
+ return errorHandler;
+ }
+
+ public void setErrorHandler(ErrorHandler errorHandler)
+ {
+ this.errorHandler = errorHandler;
+ }
+
+ public LSResourceResolver getResourceResolver()
+ {
+ return resourceResolver;
+ }
+
+ public void setResourceResolver(LSResourceResolver resourceResolver)
+ {
+ this.resourceResolver = resourceResolver;
+ }
+
+ public TypeInfoProvider getTypeInfoProvider()
+ {
+ return typeInfoProvider;
+ }
+
+ TypeInfo getElementTypeInfo()
+ {
+ return (XMLSchemaElementTypeInfo) context.getFirst();
+ }
+
+ TypeInfo getAttributeTypeInfo(int index)
+ {
+ return (XMLSchemaAttributeTypeInfo) attributes.get(index);
+ }
+
+ boolean isIdAttribute(int index)
+ {
+ XMLSchemaAttributeTypeInfo typeInfo =
+ (XMLSchemaAttributeTypeInfo) attributes.get(index);
+ return typeInfo.id;
+ }
+
+ boolean isSpecified(int index)
+ {
+ XMLSchemaAttributeTypeInfo typeInfo =
+ (XMLSchemaAttributeTypeInfo) attributes.get(index);
+ return typeInfo.specified;
+ }
+
+ public void setDocumentLocator(Locator locator)
+ {
+ loc = locator;
+ if (contentHandler != null)
+ {
+ contentHandler.setDocumentLocator(locator);
+ }
+ }
+
+ public void startDocument()
+ throws SAXException
+ {
+ namespaceSupport.reset();
+ context.clear();
+ attributes.clear();
+ if (contentHandler != null)
+ {
+ contentHandler.startDocument();
+ }
+ }
+
+ public void endDocument()
+ throws SAXException
+ {
+ if (contentHandler != null)
+ {
+ contentHandler.endDocument();
+ }
+ }
+
+ public void startPrefixMapping(String prefix, String uri)
+ throws SAXException
+ {
+ namespaceSupport.declarePrefix(prefix, uri);
+ if (contentHandler != null)
+ {
+ contentHandler.startPrefixMapping(prefix, uri);
+ }
+ }
+
+ public void endPrefixMapping(String prefix)
+ throws SAXException
+ {
+ if (contentHandler != null)
+ {
+ contentHandler.endPrefixMapping(prefix);
+ }
+ }
+
+ public void startElement(String uri, String localName, String qName,
+ Attributes atts)
+ throws SAXException
+ {
+ namespaceSupport.pushContext();
+ QName name = new QName(uri, localName);
+ ElementDeclaration decl =
+ (ElementDeclaration) schema.elementDeclarations.get(name);
+ // Validation Rule: Element Locally Valid (Element)
+ String xsiType =
+ atts.getValue(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "type");
+ xsiType = xsiType.trim(); // normalise
+ String xsiNil =
+ atts.getValue(XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI, "nil");
+ Type type = decl.datatype;
+ if (xsiType.length() > 0)
+ {
+ try
+ {
+ Type specifiedType = resolveType(xsiType);
+ // TODO 4.3
+ type = specifiedType;
+ }
+ catch (DatatypeException e) // 4.1, 4.2
+ {
+ ValidationException e2 =
+ new ValidationException("Can't resolve type " + xsiType,
+ loc);
+ e2.initCause(e);
+ throw e2;
+ }
+ }
+ XMLSchemaElementTypeInfo typeInfo =
+ new XMLSchemaElementTypeInfo(schema, decl, type);
+ if (decl == null) // 1
+ {
+ throw new ValidationException("No declaration for " + name, loc);
+ }
+ if (decl.isAbstract) // 2
+ {
+ throw new ValidationException("Declaration for " + name +
+ " is abstract", loc);
+ }
+ if (xsiNil.length() > 0)
+ {
+ if (!decl.nillable) // 3.1
+ {
+ throw new ValidationException("Declaration for " + name +
+ " is nillable but xsi:nil present",
+ loc);
+ }
+ else if ("true".equals(xsiNil)) // 3.2
+ {
+ typeInfo.nil = true;
+ if (decl.type == XMLSchema.CONSTRAINT_FIXED) // 3.2.2
+ {
+ throw new ValidationException("Declaration for " + name +
+ " is fixed but xsi:nil is true",
+ loc);
+ }
+ }
+ }
+ // TODO 5, 6, 7
+
+ // parent
+ if (!context.isEmpty())
+ {
+ XMLSchemaElementTypeInfo parent =
+ (XMLSchemaElementTypeInfo) context.getFirst();
+ if (parent.nil) // Element Locally Valid (Element) 3.2.1
+ {
+ throw new ValidationException("Parent of " + qName +
+ " is declared xsi:nil", loc);
+ }
+ // TODO
+ }
+ context.addFirst(typeInfo);
+ // attributes
+ int len = atts.getLength();
+ Attributes2Impl atts2 = new Attributes2Impl();
+ int count = 0;
+ for (int i = 0; i < len; i++)
+ {
+ String attUri = atts.getURI(i);
+ String attLocalName = atts.getLocalName(i);
+ String attQName = atts.getQName(i);
+ String attValue = atts.getValue(i);
+
+ if (XMLConstants.W3C_XML_SCHEMA_INSTANCE_NS_URI.equals(attUri))
+ {
+ continue; // ?
+ }
+
+ QName attName = new QName(attUri, attLocalName);
+ AttributeDeclaration attDecl =
+ (AttributeDeclaration) schema.attributeDeclarations.get(attName);
+ boolean declared = (attDecl != null);
+
+ String attType = (attDecl != null) ?
+ attDecl.datatype.toString() : "CDATA";
+ XMLSchemaAttributeTypeInfo attTypeInfo =
+ new XMLSchemaAttributeTypeInfo(schema, attDecl, true);
+ attributes.add(attTypeInfo);
+
+ atts2.addAttribute(attUri, attLocalName, attQName, attType, attValue);
+ atts2.setDeclared(count, declared);
+ atts2.setSpecified(count, true);
+ count++;
+ }
+ // add defaulted attributes to atts2
+ // TODO
+ // atts2.setSpecified(count, false);
+ if (contentHandler != null)
+ {
+ contentHandler.startElement(uri, localName, qName, atts2);
+ }
+ }
+
+ public void endElement(String uri, String localName, String qName)
+ throws SAXException
+ {
+ // TODO check all required have been seen
+ context.removeFirst();
+ attributes.clear();
+ namespaceSupport.popContext();
+ if (contentHandler != null)
+ {
+ contentHandler.endElement(uri, localName, qName);
+ }
+ }
+
+ public void characters(char[] ch, int start, int length)
+ throws SAXException
+ {
+ XMLSchemaElementTypeInfo parent =
+ (XMLSchemaElementTypeInfo) context.getFirst();
+ if (parent.nil) // Element Locally Valid (Element) 3.2.1
+ {
+ throw new ValidationException(parent.decl.name.toString() +
+ " is declared xsi:nil",
+ loc);
+ }
+ // TODO
+ if (contentHandler != null)
+ {
+ contentHandler.characters(ch, start, length);
+ }
+ }
+
+ public void ignorableWhitespace(char[] ch, int start, int length)
+ throws SAXException
+ {
+ if (contentHandler != null)
+ {
+ contentHandler.ignorableWhitespace(ch, start, length);
+ }
+ }
+
+ public void processingInstruction(String target, String data)
+ throws SAXException
+ {
+ if (contentHandler != null)
+ {
+ contentHandler.processingInstruction(target, data);
+ }
+ }
+
+ public void skippedEntity(String name)
+ throws SAXException
+ {
+ if (contentHandler != null)
+ {
+ contentHandler.skippedEntity(name);
+ }
+ }
+
+ Type resolveType(String value)
+ throws DatatypeException
+ {
+ QName name = QName.valueOf(value);
+ String prefix = name.getPrefix();
+ String localName = name.getLocalPart();
+ if (prefix != null && prefix.length() > 0)
+ {
+ String uri = namespaceSupport.getURI(prefix);
+ if (!XMLConstants.W3C_XML_SCHEMA_NS_URI.equals(uri))
+ return null;
+ }
+ if ("anyType".equals(localName))
+ return Type.ANY_TYPE;
+ return (SimpleType) typeLibrary.createDatatype(localName);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/AndExpr.java b/libjava/classpath/gnu/xml/xpath/AndExpr.java
new file mode 100644
index 000000000..9213a40cc
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/AndExpr.java
@@ -0,0 +1,87 @@
+/* AndExpr.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.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Logical and.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class AndExpr
+ extends Expr
+{
+
+ final Expr lhs;
+ final Expr rhs;
+
+ public AndExpr(Expr lhs, Expr rhs)
+ {
+ this.lhs = lhs;
+ this.rhs = rhs;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object left = lhs.evaluate(context, pos, len);
+ if (!_boolean(context, left))
+ {
+ return Boolean.FALSE;
+ }
+ Object right = rhs.evaluate(context, pos, len);
+ return _boolean(context, right) ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new AndExpr(lhs.clone(context), rhs.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (lhs.references(var) || rhs.references(var));
+ }
+
+ public String toString()
+ {
+ return lhs + " and " + rhs;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/ArithmeticExpr.java b/libjava/classpath/gnu/xml/xpath/ArithmeticExpr.java
new file mode 100644
index 000000000..a7bc62f2e
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/ArithmeticExpr.java
@@ -0,0 +1,170 @@
+/* ArithmeticExpr.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.xpath;
+
+import gnu.java.lang.CPStringBuilder;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Binary arithmetic expression.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class ArithmeticExpr
+ extends Expr
+{
+
+ static final int ADD = 0;
+ static final int SUBTRACT = 1;
+ static final int MULTIPLY = 2;
+ static final int DIVIDE = 3;
+ static final int MODULO = 4;
+
+ final Expr lhs;
+ final Expr rhs;
+ final int op;
+
+ ArithmeticExpr(Expr lhs, Expr rhs, int op)
+ {
+ this.lhs = lhs;
+ this.rhs = rhs;
+ switch (op)
+ {
+ case ADD:
+ case SUBTRACT:
+ case MULTIPLY:
+ case DIVIDE:
+ case MODULO:
+ this.op = op;
+ break;
+ default:
+ throw new IllegalArgumentException();
+ }
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object left = lhs.evaluate(context, pos, len);
+ Object right = rhs.evaluate(context, pos, len);
+
+ double ln = _number(context, left);
+ double rn = _number(context, right);
+ switch (op)
+ {
+ case ADD:
+ return new Double(ln + rn);
+ case SUBTRACT:
+ return new Double(ln - rn);
+ case MULTIPLY:
+ return new Double(ln * rn);
+ case DIVIDE:
+ if (rn == 0.0d || rn == -0.0d)
+ {
+ if (ln == 0.0d || ln == -0.0d)
+ {
+ return new Double(Double.NaN);
+ }
+ else
+ {
+ return new Double(ln < 0.0d ?
+ Double.NEGATIVE_INFINITY :
+ Double.POSITIVE_INFINITY);
+ }
+ }
+ return new Double(ln / rn);
+ case MODULO:
+ if (rn == 0.0d || rn == 0.0d)
+ {
+ if (ln == 0.0d || ln == -0.0d)
+ {
+ return new Double(Double.NaN);
+ }
+ else
+ {
+ return new Double(ln < 0.0d ?
+ Double.NEGATIVE_INFINITY :
+ Double.POSITIVE_INFINITY);
+ }
+ }
+ return new Double(ln % rn);
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+ public Expr clone(Object context)
+ {
+ return new ArithmeticExpr(lhs.clone(context), rhs.clone(context), op);
+ }
+
+ public boolean references(QName var)
+ {
+ return (lhs.references(var) || rhs.references(var));
+ }
+
+ public String toString()
+ {
+ CPStringBuilder buf = new CPStringBuilder();
+ buf.append(lhs);
+ buf.append(' ');
+ switch (op)
+ {
+ case ADD:
+ buf.append('+');
+ break;
+ case SUBTRACT:
+ buf.append('-');
+ break;
+ case MULTIPLY:
+ buf.append('*');
+ break;
+ case DIVIDE:
+ buf.append("div");
+ break;
+ case MODULO:
+ buf.append("mod");
+ break;
+ }
+ buf.append(' ');
+ buf.append(rhs);
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/BooleanFunction.java b/libjava/classpath/gnu/xml/xpath/BooleanFunction.java
new file mode 100644
index 000000000..05e0bd5bc
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/BooleanFunction.java
@@ -0,0 +1,95 @@
+/* BooleanFunction.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.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>boolean</code> function converts its argument to a boolean as
+ * follows:
+ * <ul>
+ * <li>a number is true if and only if it is neither positive or negative
+ * zero nor NaN</li>
+ * <li>a node-set is true if and only if it is non-empty</li>
+ * <li>a string is true if and only if its length is non-zero</li>
+ * <li>an object of a type other than the four basic types is converted to a
+ * boolean in a way that is dependent on that type</li>
+ * </ul>
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class BooleanFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ BooleanFunction(List<Expr> args)
+ {
+ this(args.get(0));
+ }
+
+ BooleanFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ return _boolean(context, val) ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new BooleanFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "boolean(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/CeilingFunction.java b/libjava/classpath/gnu/xml/xpath/CeilingFunction.java
new file mode 100644
index 000000000..aa906e0dd
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/CeilingFunction.java
@@ -0,0 +1,89 @@
+/* CeilingFunction.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.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>ceiling</code> function returns the smallest (closest to
+ * negative infinity) number that is not less than the argument and that
+ * is an integer.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class CeilingFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ CeilingFunction(List<Expr> args)
+ {
+ this(args.get(0));
+ }
+
+ CeilingFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ double n = _number(context, val);
+ return new Double(Math.ceil(n));
+ }
+
+ public Expr clone(Object context)
+ {
+ return new CeilingFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "ceiling(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/ConcatFunction.java b/libjava/classpath/gnu/xml/xpath/ConcatFunction.java
new file mode 100644
index 000000000..58096e5ac
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/ConcatFunction.java
@@ -0,0 +1,115 @@
+/* ConcatFunction.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.xpath;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>concat</code> function returns the concatenation of its arguments.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class ConcatFunction
+ extends Expr
+{
+
+ final List<Expr> args;
+
+ ConcatFunction(List<Expr> args)
+ {
+ this.args = args;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ CPStringBuilder buf = new CPStringBuilder();
+ for (Expr arg : args)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ buf.append(_string(context, val));
+ }
+ return buf.toString();
+ }
+
+ public Expr clone(Object context)
+ {
+ int len = args.size();
+ List<Expr> args2 = new ArrayList<Expr>(len);
+ for (int i = 0; i < len; i++)
+ {
+ args2.add(args.get(i).clone(context));
+ }
+ return new ConcatFunction(args2);
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator<Expr> i = args.iterator(); i.hasNext(); )
+ {
+ if (i.next().references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String toString()
+ {
+ CPStringBuilder buf = new CPStringBuilder("concat(");
+ int len = args.size();
+ for (int i = 0; i < len; i++)
+ {
+ if (i > 0)
+ {
+ buf.append(',');
+ }
+ buf.append(args.get(i));
+ }
+ buf.append(')');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Constant.java b/libjava/classpath/gnu/xml/xpath/Constant.java
new file mode 100644
index 000000000..5ed39cc05
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Constant.java
@@ -0,0 +1,98 @@
+/* Constant.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.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Constant value (string literal or number).
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class Constant
+ extends Expr
+{
+
+ final Object value;
+
+ public Constant(Object value)
+ {
+ this.value = value;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ return value;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new Constant(value);
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ String ret = value.toString();
+ if (value instanceof String)
+ {
+ if (ret.indexOf('\'') == -1)
+ {
+ return '\'' + ret + '\'';
+ }
+ else
+ {
+ return '"' + ret + '"';
+ }
+ }
+ if (value instanceof Double)
+ {
+ if (ret.endsWith(".0"))
+ {
+ ret = ret.substring(0, ret.length() - 2);
+ }
+ }
+ return ret;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/ContainsFunction.java b/libjava/classpath/gnu/xml/xpath/ContainsFunction.java
new file mode 100644
index 000000000..473d2532f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/ContainsFunction.java
@@ -0,0 +1,93 @@
+/* ContainsFunction.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.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>contains</code> function returns true if the first argument
+ * string contains the second argument string, and otherwise returns false.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class ContainsFunction
+ extends Expr
+{
+
+ final Expr arg1;
+ final Expr arg2;
+
+ ContainsFunction(List<Expr> args)
+ {
+ this(args.get(0), args.get(1));
+ }
+
+ ContainsFunction(Expr arg1, Expr arg2)
+ {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val1 = arg1.evaluate(context, pos, len);
+ Object val2 = arg2.evaluate(context, pos, len);
+ String s1 = _string(context, val1);
+ String s2 = _string(context, val2);
+ return (s1.indexOf(s2) != -1) ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new ContainsFunction(arg1.clone(context), arg2.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg1.references(var) || arg2.references(var));
+ }
+
+ public String toString()
+ {
+ return "contains(" + arg1 + "," + arg2 + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/CountFunction.java b/libjava/classpath/gnu/xml/xpath/CountFunction.java
new file mode 100644
index 000000000..e1892a058
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/CountFunction.java
@@ -0,0 +1,89 @@
+/* CountFunction.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.xpath;
+
+import java.util.Collection;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>count</code> function returns the number of nodes in the
+ * argument node-set.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class CountFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ CountFunction(List<Expr> args)
+ {
+ this(args.get(0));
+ }
+
+ CountFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ return new Double((double) ((Collection<?>) val).size());
+ }
+
+ public Expr clone(Object context)
+ {
+ return new CountFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "count(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/DocumentOrderComparator.java b/libjava/classpath/gnu/xml/xpath/DocumentOrderComparator.java
new file mode 100644
index 000000000..c4471c120
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/DocumentOrderComparator.java
@@ -0,0 +1,57 @@
+/* DocumentOrderComparator.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.xpath;
+
+import java.util.Comparator;
+import org.w3c.dom.Node;
+
+/**
+ * Sorts nodes into document order.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class DocumentOrderComparator
+ implements Comparator<Node>
+{
+
+ public int compare(Node n1, Node n2)
+ {
+ return (int) n1.compareDocumentPosition(n2);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/EqualityExpr.java b/libjava/classpath/gnu/xml/xpath/EqualityExpr.java
new file mode 100644
index 000000000..133e1ff20
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/EqualityExpr.java
@@ -0,0 +1,274 @@
+/* EqualityExpr.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.xpath;
+
+import java.util.Collection;
+import java.util.Iterator;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Boolean equality expression.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class EqualityExpr
+ extends Expr
+{
+
+ final Expr lhs;
+ final Expr rhs;
+ final boolean invert;
+
+ EqualityExpr(Expr lhs, Expr rhs, boolean invert)
+ {
+ this.lhs = lhs;
+ this.rhs = rhs;
+ this.invert = invert;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ boolean val = evaluateImpl(context, pos, len);
+ if (invert)
+ {
+ return val ? Boolean.FALSE : Boolean.TRUE;
+ }
+ else
+ {
+ return val ? Boolean.TRUE : Boolean.FALSE;
+ }
+ }
+
+ private boolean evaluateImpl(Node context, int pos, int len)
+ {
+ Object left = lhs.evaluate(context, pos, len);
+ Object right = rhs.evaluate(context, pos, len);
+
+ /*
+ * If both objects to be compared are node-sets, then the comparison
+ * will be true if and only if there is a node in the first node-set and
+ * a node in the second node-set such that the result of performing the
+ * comparison on the string-values of the two nodes is true.
+ */
+ boolean flns = left instanceof Collection;
+ boolean frns = right instanceof Collection;
+ if (flns && frns)
+ {
+ /* Suppression is safe, as we know context produces Collection<Node> */
+ @SuppressWarnings("unchecked")
+ Collection<Node> lns = (Collection<Node>) left;
+ @SuppressWarnings("unchecked")
+ Collection<Node> rns = (Collection<Node>) right;
+ if (lns.isEmpty())
+ {
+ return false;
+ }
+ boolean all = true;
+ for (Node ltest : lns)
+ {
+ for (Node rtest : rns)
+ {
+ if (ltest == rtest || ltest.equals(rtest))
+ {
+ // much shorter
+ if (!invert)
+ {
+ return true;
+ }
+ }
+ else if (stringValue(ltest).equals(stringValue(rtest)))
+ {
+ if (!invert)
+ {
+ return true;
+ }
+ }
+ else
+ {
+ all = false;
+ }
+ }
+ }
+ return all;
+ }
+ /*
+ * If one object to be compared is a node-set and the other is a number,
+ * then the comparison will be true if and only if there is a node in
+ * the node-set such that the result of performing the comparison on the
+ * number to be compared and on the result of converting the
+ * string-value of that node to a number using the number function is
+ * true.
+ */
+ boolean fln = left instanceof Double;
+ boolean frn = right instanceof Double;
+ if ((flns && frn) || (frns && fln))
+ {
+ /* Suppression is safe, as we know context produces Collection<Node> */
+ @SuppressWarnings("unchecked")
+ Collection<Node> ns = flns ? (Collection<Node>) left : (Collection<Node>) right;
+ double n = fln ? ((Double) left).doubleValue() :
+ ((Double) right).doubleValue();
+ boolean all = true;
+ for (Node test : ns)
+ {
+ double nn = _number(context, stringValue(test));
+ if (nn == n)
+ {
+ if (!invert)
+ {
+ return true;
+ }
+ }
+ else
+ {
+ all = false;
+ }
+ }
+ return invert ? all : false;
+ }
+ /*
+ * If one object to be compared is a node-set and the other is a
+ * string, then the comparison will be true if and only if there is a
+ * node in the node-set such that the result of performing the
+ * comparison on the string-value of the node and the other string is
+ * true.
+ */
+ boolean fls = left instanceof String;
+ boolean frs = right instanceof String;
+ if ((flns && frs) || (frns && fls))
+ {
+ /* Suppression is safe, as we know context produces Collection<Node> */
+ @SuppressWarnings("unchecked")
+ Collection<Node> ns = flns ? (Collection<Node>) left : (Collection<Node>) right;
+ String s = fls ? (String) left : (String) right;
+ boolean all = true;
+ for (Node test : ns)
+ {
+ if (stringValue(test).equals(s))
+ {
+ if (!invert)
+ {
+ return true;
+ }
+ }
+ else
+ {
+ all = false;
+ }
+ }
+ return invert ? all : false;
+ }
+ /*
+ * If one object to be compared is a node-set and the other is a
+ * boolean, then the comparison will be true if and only if the result
+ * of performing the comparison on the boolean and on the result of
+ * converting the node-set to a boolean using the boolean function is
+ * true.
+ */
+ boolean flb = left instanceof Boolean;
+ boolean frb = right instanceof Boolean;
+ if ((flns && frb) || (frns && flb))
+ {
+ /* Suppression is safe, as we know context produces Collection<Node> */
+ @SuppressWarnings("unchecked")
+ Collection<Node> ns = flns ? (Collection<Node>) left : (Collection<Node>) right;
+ boolean b = flb ? ((Boolean) left).booleanValue() :
+ ((Boolean) right).booleanValue();
+ return _boolean(context, ns) == b;
+ }
+ /*
+ * If at least one object to be compared is a boolean, then each object
+ * to be compared is converted to a boolean as if by applying the
+ * boolean function.
+ */
+ if (flb || frb)
+ {
+ boolean lb = flb ? ((Boolean) left).booleanValue() :
+ _boolean(context, left);
+ boolean rb = frb ? ((Boolean) right).booleanValue() :
+ _boolean(context, right);
+ return lb == rb;
+ }
+ /*
+ * Otherwise, if at least one object to be compared is
+ * a number, then each object to be compared is converted to a number as
+ * if by applying the number function.
+ */
+ if (fln || frn)
+ {
+ double ln = fln ? ((Double) left).doubleValue() :
+ _number(context, left);
+ double rn = frn ? ((Double) right).doubleValue() :
+ _number(context, right);
+ return ln == rn;
+ }
+ /*
+ * Otherwise, both objects to be
+ * compared are converted to strings as if by applying the string
+ * function.
+ */
+ String ls = fls ? (String) left : _string(context, left);
+ String rs = frs ? (String) right : _string(context, right);
+ return ls.equals(rs);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new EqualityExpr(lhs.clone(context), rhs.clone(context), invert);
+ }
+
+ public boolean references(QName var)
+ {
+ return (lhs.references(var) || rhs.references(var));
+ }
+
+ public String toString()
+ {
+ if (invert)
+ {
+ return lhs + " != " + rhs;
+ }
+ else
+ {
+ return lhs + " = " + rhs;
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Expr.java b/libjava/classpath/gnu/xml/xpath/Expr.java
new file mode 100644
index 000000000..0e98f43f5
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Expr.java
@@ -0,0 +1,549 @@
+/* Expr.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.xpath;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.io.IOException;
+import java.text.DecimalFormat;
+import java.text.DecimalFormatSymbols;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Locale;
+import java.util.Set;
+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.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import org.xml.sax.SAXException;
+
+/**
+ * An XPath expression.
+ * This can be evaluated in the context of a node to produce a result.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public abstract class Expr
+ implements XPathExpression
+{
+
+ protected static final Comparator<Node> documentOrderComparator =
+ new DocumentOrderComparator();
+
+ protected static final DecimalFormat decimalFormat =
+ new DecimalFormat("####################################################" +
+ ".####################################################",
+ new DecimalFormatSymbols(Locale.US));
+
+ static class ExprNodeSet implements NodeList
+ {
+
+ private ArrayList<Node> list;
+
+ ExprNodeSet(Collection<Node> collection)
+ {
+ if (collection instanceof ArrayList)
+ list = (ArrayList<Node>) collection;
+ else
+ list = new ArrayList<Node>(collection);
+ }
+
+ public int getLength()
+ {
+ return list.size();
+ }
+
+ public Node item(int index)
+ {
+ try
+ {
+ return list.get(index);
+ }
+ catch (ArrayIndexOutOfBoundsException e)
+ {
+ return null;
+ }
+ }
+
+ }
+
+ public Object evaluate(Object item, QName returnType)
+ throws XPathExpressionException
+ {
+ Object ret = null;
+ Node context = null;
+ if (item instanceof Node)
+ {
+ context = (Node) item;
+ ret = evaluate(context, 1, 1);
+ if (XPathConstants.STRING == returnType &&
+ !(ret instanceof String))
+ {
+ ret = _string(context, ret);
+ }
+ else if (XPathConstants.NUMBER == returnType &&
+ !(ret instanceof Double))
+ {
+ ret = new Double(_number(context, ret));
+ }
+ else if (XPathConstants.BOOLEAN == returnType &&
+ !(ret instanceof Boolean))
+ {
+ ret = _boolean(context, ret) ? Boolean.TRUE : Boolean.FALSE;
+ }
+ else if (XPathConstants.NODE == returnType)
+ {
+ if (ret instanceof Collection)
+ {
+ /* Suppression is safe, as we know context
+ produces Collection<Node> */
+ @SuppressWarnings("unchecked")
+ Collection<Node> ns = (Collection<Node>) ret;
+ switch (ns.size())
+ {
+ case 0:
+ ret = null;
+ break;
+ case 1:
+ ret = ns.iterator().next();
+ break;
+ default:
+ throw new XPathExpressionException("multiple nodes in node-set");
+ }
+ }
+ else if (ret != null)
+ {
+ throw new XPathExpressionException("return value is not a node-set");
+ }
+ }
+ else if (XPathConstants.NODESET == returnType)
+ {
+ if (ret != null && !(ret instanceof Collection))
+ {
+ throw new XPathExpressionException("return value is not a node-set");
+ }
+ if (ret != null)
+ {
+ /* Suppression is safe, as we know context produces Collection<Node> */
+ @SuppressWarnings("unchecked")
+ Collection<Node> nodes = (Collection<Node>) ret;
+ ret = new ExprNodeSet(nodes);
+ }
+ }
+ }
+ return ret;
+ }
+
+ public String evaluate(Object item)
+ throws XPathExpressionException
+ {
+ return (String) evaluate(item, XPathConstants.STRING);
+ }
+
+ public Object evaluate(InputSource source, QName returnType)
+ throws XPathExpressionException
+ {
+ try
+ {
+ DocumentBuilderFactory factory =
+ new gnu.xml.dom.JAXPFactory();
+ DocumentBuilder builder = factory.newDocumentBuilder();
+ Document doc = builder.parse(source);
+ return evaluate(doc, returnType);
+ }
+ catch (ParserConfigurationException e)
+ {
+ throw new XPathExpressionException(e);
+ }
+ catch (SAXException e)
+ {
+ throw new XPathExpressionException(e);
+ }
+ catch (IOException e)
+ {
+ throw new XPathExpressionException(e);
+ }
+ }
+
+ public String evaluate(InputSource source)
+ throws XPathExpressionException
+ {
+ return (String) evaluate(source, XPathConstants.STRING);
+ }
+
+ public abstract Object evaluate(Node context, int pos, int len);
+
+ public abstract Expr clone(Object context);
+
+ public abstract boolean references(QName var);
+
+ /* -- 4.1 Node Set Functions -- */
+
+ /**
+ * The id function selects elements by their unique ID.
+ * When the argument to id is of type node-set, then the result is
+ * the union of the result of applying id to the string-value of each of
+ * the nodes in the argument node-set. When the argument to id is of any
+ * other type, the argument is converted to a string as if by a call to
+ * the string function; the string is split into a whitespace-separated
+ * list of tokens (whitespace is any sequence of characters matching the
+ * production S); the result is a node-set containing the elements in the
+ * same document as the context node that have a unique ID equal to any of
+ * the tokens in the list.
+ */
+ public static Collection<Node> _id(Node context, Object object)
+ {
+ Set<Node> ret = new HashSet<Node>();
+ if (object instanceof Collection)
+ {
+ /* Suppression is safe, as the iteration will check each value is a Node */
+ @SuppressWarnings("unchecked")
+ Collection<Node> nodeSet = (Collection<Node>) object;
+ for (Iterator<Node> i = nodeSet.iterator(); i.hasNext(); )
+ {
+ String string = stringValue(i.next());
+ ret.addAll(_id (context, string));
+ }
+ }
+ else
+ {
+ Document doc = (context instanceof Document) ? (Document) context :
+ context.getOwnerDocument();
+ String string = _string(context, object);
+ StringTokenizer st = new StringTokenizer(string, " \t\r\n");
+ while (st.hasMoreTokens())
+ {
+ Node element = doc.getElementById(st.nextToken());
+ if (element != null)
+ {
+ ret.add(element);
+ }
+ }
+ }
+ return ret;
+ }
+
+ /**
+ * The local-name function returns the local part of the expanded-name of
+ * the node in the argument node-set that is first in document order. If
+ * the argument node-set is empty or the first node has no expanded-name,
+ * an empty string is returned. If the argument is omitted, it defaults to
+ * a node-set with the context node as its only member.
+ */
+ public static String _local_name(Node context, Collection<Node> nodeSet)
+ {
+ if (nodeSet == null || nodeSet.isEmpty())
+ return "";
+ Node node = firstNode(nodeSet);
+ String ret = node.getLocalName();
+ return (ret == null) ? "" : ret;
+ }
+
+ /**
+ * The namespace-uri function returns the namespace URI of the
+ * expanded-name of the node in the argument node-set that is first in
+ * document order. If the argument node-set is empty, the first node has
+ * no expanded-name, or the namespace URI of the expanded-name is null, an
+ * empty string is returned. If the argument is omitted, it defaults to a
+ * node-set with the context node as its only member.
+ */
+ public static String _namespace_uri(Node context, Collection<Node> nodeSet)
+ {
+ if (nodeSet == null || nodeSet.isEmpty())
+ return "";
+ Node node = firstNode(nodeSet);
+ String ret = node.getNamespaceURI();
+ return (ret == null) ? "" : ret;
+ }
+
+ /**
+ * The name function returns a string containing a QName representing the
+ * expanded-name of the node in the argument node-set that is first in
+ * document order. The QName must represent the expanded-name with respect
+ * to the namespace declarations in effect on the node whose expanded-name
+ * is being represented. Typically, this will be the QName that occurred
+ * in the XML source. This need not be the case if there are namespace
+ * declarations in effect on the node that associate multiple prefixes
+ * with the same namespace. However, an implementation may include
+ * information about the original prefix in its representation of nodes;
+ * in this case, an implementation can ensure that the returned string is
+ * always the same as the QName used in the XML source. If the argument
+ * node-set is empty or the first node has no expanded-name, an empty
+ * string is returned. If the argument it omitted, it defaults to a
+ * node-set with the context node as its only member.
+ */
+ public static String _name(Node context, Collection<Node> nodeSet)
+ {
+ if (nodeSet == null || nodeSet.isEmpty())
+ return "";
+ Node node = firstNode(nodeSet);
+ String ret = null;
+ switch (node.getNodeType())
+ {
+ case Node.ATTRIBUTE_NODE:
+ case Node.ELEMENT_NODE:
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ ret = node.getNodeName();
+ }
+ return (ret == null) ? "" : ret;
+ }
+
+ /**
+ * Returns the first node in the set in document order.
+ */
+ static Node firstNode(Collection<Node> nodeSet)
+ {
+ List<Node> list = new ArrayList<Node>(nodeSet);
+ Collections.sort(list, documentOrderComparator);
+ return list.get(0);
+ }
+
+ /* -- 4.2 String Functions -- */
+
+ /**
+ * Implementation of the XPath <code>string</code> function.
+ */
+ public static String _string(Node context, Object object)
+ {
+ if (object == null)
+ {
+ return stringValue(context);
+ }
+ if (object instanceof String)
+ {
+ return (String) object;
+ }
+ if (object instanceof Boolean)
+ {
+ return object.toString();
+ }
+ if (object instanceof Double)
+ {
+ double d = ((Double) object).doubleValue();
+ if (Double.isNaN(d))
+ {
+ return "NaN";
+ }
+ else if (d == 0.0d)
+ {
+ return "0";
+ }
+ else if (Double.isInfinite(d))
+ {
+ if (d < 0)
+ {
+ return "-Infinity";
+ }
+ else
+ {
+ return "Infinity";
+ }
+ }
+ else
+ {
+ String ret = decimalFormat.format(d);
+ if (ret.endsWith (".0"))
+ {
+ ret = ret.substring(0, ret.length() - 2);
+ }
+ return ret;
+ }
+ }
+ if (object instanceof Collection)
+ {
+ /* Suppression is safe, as we fail immediately if the
+ * first element is not a Node and don't use the rest */
+ @SuppressWarnings("unchecked")
+ Collection<Node> nodeSet = (Collection<Node>) object;
+ if (nodeSet.isEmpty())
+ {
+ return "";
+ }
+ Node node = firstNode(nodeSet);
+ return stringValue(node);
+ }
+ throw new IllegalArgumentException(object.toString());
+ }
+
+ /* -- 4.3 Boolean Functions -- */
+
+ /**
+ * Implementation of the XPath <code>boolean</code> function.
+ */
+ public static boolean _boolean(Node context, Object object)
+ {
+ if (object instanceof Boolean)
+ {
+ return ((Boolean) object).booleanValue();
+ }
+ if (object instanceof Double)
+ {
+ Double value = (Double) object;
+ if (value.isNaN())
+ return false;
+ return value.doubleValue() != 0.0;
+ }
+ if (object instanceof String)
+ {
+ return ((String) object).length() != 0;
+ }
+ if (object instanceof Collection)
+ {
+ return ((Collection<?>) object).size() != 0;
+ }
+ return false; // TODO user defined types
+ }
+
+ /* -- 4.4 Number Functions -- */
+
+ /**
+ * Implementation of the XPath <code>number</code> function.
+ */
+ public static double _number(Node context, Object object)
+ {
+ if (object == null)
+ {
+ object = Collections.singleton(context);
+ }
+ if (object instanceof Double)
+ {
+ return ((Double) object).doubleValue();
+ }
+ if (object instanceof Boolean)
+ {
+ return ((Boolean) object).booleanValue() ? 1.0 : 0.0;
+ }
+ if (object instanceof Collection)
+ {
+ /* Suppression is safe, as we fail immediately if one
+ * of the elements is not a Node */
+ @SuppressWarnings("unchecked")
+ Collection<Node> nodeSet = (Collection<Node>) object;
+ // Convert node-set to string
+ object = stringValue(nodeSet);
+ }
+ if (object instanceof String)
+ {
+ String string = ((String) object).trim();
+ try
+ {
+ return Double.parseDouble(string);
+ }
+ catch (NumberFormatException e)
+ {
+ return Double.NaN;
+ }
+ }
+ return Double.NaN; // TODO user-defined types
+ }
+
+ /**
+ * Computes the XPath string-value of the specified node-set.
+ */
+ public static String stringValue(Collection<Node> nodeSet)
+ {
+ CPStringBuilder buf = new CPStringBuilder();
+ for (Iterator<Node> i = nodeSet.iterator(); i.hasNext(); )
+ {
+ buf.append(stringValue(i.next()));
+ }
+ return buf.toString();
+ }
+
+ /**
+ * Computes the XPath string-value of the specified node.
+ */
+ public static String stringValue(Node node)
+ {
+ return stringValue(node, false);
+ }
+
+ static String stringValue(Node node, boolean elementMode)
+ {
+ switch (node.getNodeType())
+ {
+ case Node.DOCUMENT_NODE: // 5.1 Root Node
+ case Node.DOCUMENT_FRAGMENT_NODE:
+ case Node.ELEMENT_NODE: // 5.2 Element Nodes
+ CPStringBuilder buf = new CPStringBuilder();
+ for (Node ctx = node.getFirstChild(); ctx != null;
+ ctx = ctx.getNextSibling())
+ {
+ buf.append(stringValue(ctx, true));
+ }
+ return buf.toString();
+ case Node.TEXT_NODE: // 5.7 Text Nodes
+ case Node.CDATA_SECTION_NODE:
+ return node.getNodeValue();
+ case Node.ATTRIBUTE_NODE: // 5.3 Attribute Nodes
+ case Node.PROCESSING_INSTRUCTION_NODE: // 5.5 Processing Instruction
+ case Node.COMMENT_NODE: // 5.6 Comment Nodes
+ if (!elementMode)
+ {
+ return node.getNodeValue();
+ }
+ default:
+ return "";
+ }
+ }
+
+ static int intValue(Object val)
+ {
+ if (val instanceof Double)
+ {
+ Double d = (Double) val;
+ return d.isNaN() ? 0 : d.intValue();
+ }
+ else
+ return (int) Math.ceil(_number(null, val));
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/FalseFunction.java b/libjava/classpath/gnu/xml/xpath/FalseFunction.java
new file mode 100644
index 000000000..9a20f9163
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/FalseFunction.java
@@ -0,0 +1,72 @@
+/* FalseFunction.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.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>false</code> function returns false.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class FalseFunction
+ extends Expr
+{
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ return Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new FalseFunction();
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ return "false()";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/FloorFunction.java b/libjava/classpath/gnu/xml/xpath/FloorFunction.java
new file mode 100644
index 000000000..ed61742a3
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/FloorFunction.java
@@ -0,0 +1,90 @@
+/* FloorFunction.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.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>floor</code> function returns the largest (closest to positive
+ * infinity) number that is not greater than the argument and that is an
+ * integer.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class FloorFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ FloorFunction(List<Expr> args)
+ {
+ this(args.get(0));
+ }
+
+ FloorFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ double n = _number(context, val);
+ return new Double(Math.floor(n));
+ }
+
+ public Expr clone(Object context)
+ {
+ return new FloorFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "floor(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Function.java b/libjava/classpath/gnu/xml/xpath/Function.java
new file mode 100644
index 000000000..f9eab2b73
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Function.java
@@ -0,0 +1,56 @@
+/* Function.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.xpath;
+
+import java.util.List;
+
+/**
+ * Interface to be implemented by external functions that need to receive
+ * parameter values.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public interface Function
+{
+
+ /**
+ * Sets the list of expressions to evaluate as parameter values.
+ */
+ void setArguments(List<Expr> args);
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/FunctionCall.java b/libjava/classpath/gnu/xml/xpath/FunctionCall.java
new file mode 100644
index 000000000..977482a8f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/FunctionCall.java
@@ -0,0 +1,169 @@
+/* FunctionCall.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.xpath;
+
+import gnu.java.lang.CPStringBuilder;
+
+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 javax.xml.xpath.XPathFunctionResolver;
+import org.w3c.dom.Node;
+
+/**
+ * Executes an XPath core or extension function.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class FunctionCall
+ extends Expr
+{
+
+ final XPathFunctionResolver resolver;
+ final String name;
+ final List<Expr> args;
+
+ public FunctionCall(XPathFunctionResolver resolver, String name)
+ {
+ this(resolver, name, null);
+ }
+
+ public FunctionCall(XPathFunctionResolver resolver, String name, List<Expr> args)
+ {
+ this.resolver = resolver;
+ this.name = name;
+ if (args == null)
+ this.args = Collections.emptyList();
+ else
+ this.args = args;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ if (resolver != null)
+ {
+ QName qname = QName.valueOf(name);
+ int arity = args.size();
+ XPathFunction function = resolver.resolveFunction(qname, arity);
+ if (function != null)
+ {
+ //System.err.println("Calling "+toString()+" with "+values);
+ if (function instanceof Expr)
+ {
+ if (function instanceof Function)
+ {
+ ((Function) function).setArguments(args);
+ }
+ return ((Expr) function).evaluate(context, pos, len);
+ }
+ else
+ {
+ List<Object> values = new ArrayList<Object>(arity);
+ for (int i = 0; i < arity; i++)
+ {
+ Expr arg = (Expr) args.get(i);
+ values.add(arg.evaluate(context, pos, len));
+ }
+ try
+ {
+ return function.evaluate(values);
+ }
+ catch (XPathFunctionException e)
+ {
+ e.printStackTrace(System.err); // FIXME
+ throw new RuntimeException(e.getMessage(), e);
+ }
+ }
+ }
+ }
+ throw new IllegalArgumentException("Invalid function call: " +
+ toString());
+ }
+
+ public Expr clone(Object context)
+ {
+ int len = args.size();
+ List<Expr> args2 = new ArrayList<Expr>(len);
+ for (int i = 0; i < len; i++)
+ {
+ args2.add(args.get(i).clone(context));
+ }
+ XPathFunctionResolver r = resolver;
+ if (context instanceof XPathFunctionResolver)
+ {
+ r = (XPathFunctionResolver) context;
+ }
+ return new FunctionCall(r, name, args2);
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator<Expr> i = args.iterator(); i.hasNext(); )
+ {
+ if (i.next().references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String toString()
+ {
+ CPStringBuilder buf = new CPStringBuilder();
+ buf.append(name);
+ buf.append('(');
+ int len = args.size();
+ for (int i = 0; i < len; i++)
+ {
+ if (i > 0)
+ {
+ buf.append(',');
+ }
+ buf.append(args.get(i));
+ }
+ buf.append(')');
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/IdFunction.java b/libjava/classpath/gnu/xml/xpath/IdFunction.java
new file mode 100644
index 000000000..7b6c6ac25
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/IdFunction.java
@@ -0,0 +1,103 @@
+/* IdFunction.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.xpath;
+
+import java.util.Collection;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>id</code> function selects elements by their unique ID.
+ * When the argument to id is of type node-set, then the result is
+ * the union of the result of applying id to the string-value of each of the
+ * nodes in the argument node-set. When the argument to id is of any other
+ * type, the argument is converted to a string as if by a call to the string
+ * function; the string is split into a whitespace-separated list of tokens
+ * (whitespace is any sequence of characters matching the production S); the
+ * result is a node-set containing the elements in the same document as the
+ * context node that have a unique ID equal to any of the tokens in the
+ * list.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class IdFunction
+ extends Pattern
+{
+
+ final Expr arg;
+
+ IdFunction(List<Expr> args)
+ {
+ this(args.get(0));
+ }
+
+ public IdFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public boolean matches(Node context)
+ {
+ Object ret = evaluate(context, 1, 1);
+ return !((Collection<?>) ret).isEmpty();
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ return _id(context, val);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new IdFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "id(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/LangFunction.java b/libjava/classpath/gnu/xml/xpath/LangFunction.java
new file mode 100644
index 000000000..5a8d32fc0
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/LangFunction.java
@@ -0,0 +1,123 @@
+/* LangFunction.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.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Element;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>lang</code> function returns true or false depending on whether
+ * the language of the context node as specified by xml:lang attributes is
+ * the same as or is a sublanguage of the language specified by the argument
+ * string. The language of the context node is determined by the value of
+ * the xml:lang attribute on the context node, or, if the context node has
+ * no xml:lang attribute, by the value of the xml:lang attribute on the
+ * nearest ancestor of the context node that has an xml:lang attribute. If
+ * there is no such attribute, then lang returns false. If there is such an
+ * attribute, then lang returns true if the attribute value is equal to the
+ * argument ignoring case, or if there is some suffix starting with - such
+ * that the attribute value is equal to the argument ignoring that suffix of
+ * the attribute value and ignoring case.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class LangFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ LangFunction(List<Expr> args)
+ {
+ this(args.get(0));
+ }
+
+ LangFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ String lang = _string(context, val);
+ String clang = getLang(context);
+ while (clang == null && context != null)
+ {
+ context = context.getParentNode();
+ clang = getLang(context);
+ }
+ boolean ret = (clang == null) ? false :
+ clang.toLowerCase().startsWith(lang.toLowerCase());
+ return ret ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ String getLang(Node node)
+ {
+ while (node != null)
+ {
+ if (node.getNodeType() == Node.ELEMENT_NODE)
+ {
+ String lang = ((Element) node).getAttribute("xml:lang");
+ if (lang != null)
+ return lang;
+ }
+ node = node.getParentNode();
+ }
+ return null;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new IdFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "lang(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/LastFunction.java b/libjava/classpath/gnu/xml/xpath/LastFunction.java
new file mode 100644
index 000000000..51f988f3c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/LastFunction.java
@@ -0,0 +1,73 @@
+/* LastFunction.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.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>last</code> function returns a number equal to the context
+ * size from the expression evaluation context.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class LastFunction
+ extends Expr
+{
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ return new Double((double) len);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new LastFunction();
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ return "last()";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/LocalNameFunction.java b/libjava/classpath/gnu/xml/xpath/LocalNameFunction.java
new file mode 100644
index 000000000..d829075c7
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/LocalNameFunction.java
@@ -0,0 +1,98 @@
+/* LocalNameFunction.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.xpath;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>local-name</code> function returns the local part of the
+ * expanded-name of the node in the argument node-set that is first in
+ * document order.
+ * If the argument node-set is empty or the first node has no expanded-name,
+ * an empty string is returned. If the argument is omitted, it defaults to a
+ * node-set with the context node as its only member.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class LocalNameFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ LocalNameFunction(List<Expr> args)
+ {
+ this(args.size() > 0 ? args.get(0) : null);
+ }
+
+ LocalNameFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ /* Suppression is safe, as we know context produces Collection<Node> */
+ @SuppressWarnings("unchecked")
+ Collection<Node> val = (arg == null) ? Collections.singleton(context) :
+ (Collection<Node>) arg.evaluate(context, pos, len);
+ return _local_name(context, val);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new LocalNameFunction((arg == null) ? null :
+ arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg == null) ? false : arg.references(var);
+ }
+
+ public String toString()
+ {
+ return (arg == null) ? "local-name()" : "local-name(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NameFunction.java b/libjava/classpath/gnu/xml/xpath/NameFunction.java
new file mode 100644
index 000000000..7db0be531
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NameFunction.java
@@ -0,0 +1,109 @@
+/* NameFunction.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.xpath;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>name</code> function returns a string containing a QName
+ * representing the expanded-name of the node in the argument node-set that
+ * is first in document order. The QName must represent the expanded-name
+ * with respect to the namespace declarations in effect on the node whose
+ * expanded-name is being represented. Typically, this will be the QName
+ * that occurred in the XML source. This need not be the case if there are
+ * namespace declarations in effect on the node that associate multiple
+ * prefixes with the same namespace. However, an implementation may include
+ * information about the original prefix in its representation of nodes; in
+ * this case, an implementation can ensure that the returned string is
+ * always the same as the QName used in the XML source. If the argument
+ * node-set is empty or the first node has no expanded-name, an empty string
+ * is returned. If the argument it omitted, it defaults to a node-set with
+ * the context node as its only member.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NameFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ NameFunction(List<Expr> args)
+ {
+ this(args.size() > 0 ? args.get(0) : null);
+ }
+
+ NameFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ /* Suppression is safe, as we know context produces Collection<Node> */
+ @SuppressWarnings("unchecked")
+ Collection<Node> val = (arg == null) ? Collections.singleton(context) :
+ (Collection<Node>) arg.evaluate(context, pos, len);
+ return _name(context, val);
+ }
+
+ @Override
+ public Expr clone(Object context)
+ {
+ return new NameFunction((arg == null) ? null :
+ arg.clone(context));
+ }
+
+ @Override
+ public boolean references(QName var)
+ {
+ return (arg == null) ? false : arg.references(var);
+ }
+
+ @Override
+ public String toString()
+ {
+ return (arg == null) ? "name()" : "name(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NameTest.java b/libjava/classpath/gnu/xml/xpath/NameTest.java
new file mode 100644
index 000000000..8bd06bd3b
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NameTest.java
@@ -0,0 +1,143 @@
+/* NameTest.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.xpath;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Tests whether a node has the specified name.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class NameTest
+ extends Test
+{
+
+ final QName qName;
+ final boolean anyLocalName;
+ final boolean any;
+
+ public NameTest(QName qName, boolean anyLocalName, boolean any)
+ {
+ this.anyLocalName = anyLocalName;
+ this.any = any;
+ this.qName = qName;
+ }
+
+ public boolean matchesAny()
+ {
+ return any;
+ }
+
+ public boolean matchesAnyLocalName()
+ {
+ return anyLocalName;
+ }
+
+ public boolean matches(Node node, int pos, int len)
+ {
+ switch (node.getNodeType())
+ {
+ case Node.ATTRIBUTE_NODE:
+ // Do not match namespace attributes
+ String uri = node.getNamespaceURI();
+ if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(node.getPrefix()) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(node.getNodeName()))
+ {
+ return false;
+ }
+ // Fall through
+ case Node.ELEMENT_NODE:
+ break;
+ default:
+ return false;
+ }
+ if (any)
+ return true;
+ String uri = qName.getNamespaceURI();
+ String nodeUri = node.getNamespaceURI();
+ if (!equal(uri, nodeUri))
+ return false;
+ if (anyLocalName)
+ return true;
+ String localName = qName.getLocalPart();
+ String nodeLocalName = getLocalName(node);
+ return (localName.equals(nodeLocalName));
+ }
+
+ static String getLocalName(Node node)
+ {
+ String localName = node.getLocalName();
+ if (localName == null)
+ {
+ localName = node.getNodeName();
+ int ci = localName.indexOf(':');
+ if (ci != -1)
+ localName = localName.substring(ci + 1);
+ }
+ return localName;
+ }
+
+ static boolean equal(String s1, String s2)
+ {
+ return (((s1 == null || s1.length() == 0) &&
+ (s2 == null || s2.length() == 0)) ||
+ s1 != null && s1.equals(s2));
+ }
+
+ public Test clone(Object context)
+ {
+ return new NameTest(qName, anyLocalName, any);
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString ()
+ {
+ if (any)
+ return "*";
+ return qName.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NamespaceTest.java b/libjava/classpath/gnu/xml/xpath/NamespaceTest.java
new file mode 100644
index 000000000..2f4fec179
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NamespaceTest.java
@@ -0,0 +1,120 @@
+/* NamespaceTest.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.xpath;
+
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Tests whether a namespace attribute has the specified name.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class NamespaceTest
+ extends Test
+{
+
+ final QName qName;
+ final boolean anyLocalName;
+ final boolean any;
+
+ public NamespaceTest(QName qName, boolean anyLocalName, boolean any)
+ {
+ this.anyLocalName = anyLocalName;
+ this.any = any;
+ this.qName = qName;
+ }
+
+ public boolean matchesAny()
+ {
+ return any;
+ }
+
+ public boolean matchesAnyLocalName()
+ {
+ return anyLocalName;
+ }
+
+ public boolean matches(Node node, int pos, int len)
+ {
+ switch (node.getNodeType())
+ {
+ case Node.ATTRIBUTE_NODE:
+ // Only match namespace attributes
+ String uri = node.getNamespaceURI();
+ if (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(node.getPrefix()) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(node.getNodeName()))
+ break;
+ // Fall through
+ default:
+ // Only process namespace attributes
+ return false;
+ }
+ if (any)
+ return true;
+ String uri = qName.getNamespaceURI();
+ String nodeUri = node.getNamespaceURI();
+ if (!NameTest.equal(uri, nodeUri))
+ return false;
+ if (anyLocalName)
+ return true;
+ String localName = qName.getLocalPart();
+ String nodeLocalName = NameTest.getLocalName(node);
+ return (localName.equals(nodeLocalName));
+ }
+
+ public Test clone(Object context)
+ {
+ return new NamespaceTest(qName, anyLocalName, any);
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString ()
+ {
+ if (any)
+ return "*";
+ return qName.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NamespaceUriFunction.java b/libjava/classpath/gnu/xml/xpath/NamespaceUriFunction.java
new file mode 100644
index 000000000..4972b0607
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NamespaceUriFunction.java
@@ -0,0 +1,98 @@
+/* NamespaceUriFunction.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.xpath;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>namespace-uri</code> function returns the namespace URI of the
+ * expanded-name of the node in the argument node-set that is first in
+ * document order. If the argument node-set is empty, the first node has no
+ * expanded-name, or the namespace URI of the expanded-name is null, an
+ * empty string is returned. If the argument is omitted, it defaults to a
+ * node-set with the context node as its only member.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NamespaceUriFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ NamespaceUriFunction(List<Expr> args)
+ {
+ this(args.size() > 0 ? args.get(0) : null);
+ }
+
+ NamespaceUriFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ /* Suppression is safe, as we know context produces Collection<Node> */
+ @SuppressWarnings("unchecked")
+ Collection<Node> val = (arg == null) ? Collections.singleton(context) :
+ (Collection<Node>) arg.evaluate(context, pos, len);
+ return _namespace_uri(context, val);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new NamespaceUriFunction((arg == null) ? null :
+ arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg == null) ? false : arg.references(var);
+ }
+
+ public String toString()
+ {
+ return (arg == null) ? "namespace-uri()" : "namespace-uri(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NegativeExpr.java b/libjava/classpath/gnu/xml/xpath/NegativeExpr.java
new file mode 100644
index 000000000..215ef3fa9
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NegativeExpr.java
@@ -0,0 +1,81 @@
+/* NegativeExpr.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.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Unary negative.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NegativeExpr
+ extends Expr
+{
+
+ final Expr expr;
+
+ NegativeExpr(Expr expr)
+ {
+ this.expr = expr;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = expr.evaluate(context, pos, len);
+ double n = _number(context, val);
+ return new Double(-n);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new NegativeExpr(expr.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return expr.references(var);
+ }
+
+ public String toString()
+ {
+ return "-" + expr;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NodeTypeTest.java b/libjava/classpath/gnu/xml/xpath/NodeTypeTest.java
new file mode 100644
index 000000000..43e26994b
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NodeTypeTest.java
@@ -0,0 +1,141 @@
+/* NodeTypeTest.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.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+import org.w3c.dom.ProcessingInstruction;
+
+/**
+ * Tests whether a node is of a given type.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class NodeTypeTest
+ extends Test
+{
+
+ final short type;
+ final String data;
+
+ public NodeTypeTest(short type)
+ {
+ this(type, null);
+ }
+
+ public NodeTypeTest(short type, String data)
+ {
+ this.type = type;
+ this.data = data;
+ }
+
+ public short getNodeType()
+ {
+ return type;
+ }
+
+ public String getData()
+ {
+ return data;
+ }
+
+ public boolean matches(Node node, int pos, int len)
+ {
+ short nodeType = node.getNodeType();
+ switch (nodeType)
+ {
+ case Node.ELEMENT_NODE:
+ case Node.ATTRIBUTE_NODE:
+ case Node.TEXT_NODE:
+ case Node.CDATA_SECTION_NODE:
+ case Node.COMMENT_NODE:
+ case Node.DOCUMENT_NODE:
+ if (type > 0)
+ {
+ if (nodeType != type)
+ return false;
+ }
+ return true;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ if (type > 0)
+ {
+ if (nodeType != type)
+ return false;
+ if (data != null &&
+ !data.equals(((ProcessingInstruction) node).getTarget()))
+ return false;
+ }
+ return true;
+ default:
+ // Not part of XPath data model
+ return false;
+ }
+ }
+
+ public Test clone(Object context)
+ {
+ return new NodeTypeTest(type, data);
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ switch (type)
+ {
+ case 0:
+ return "node()";
+ case Node.TEXT_NODE:
+ return "text()";
+ case Node.COMMENT_NODE:
+ return "comment()";
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ if (data != null)
+ {
+ return "processing-instruction('" + data + "')";
+ }
+ return "processing-instruction()";
+ default:
+ throw new IllegalStateException();
+ }
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NormalizeSpaceFunction.java b/libjava/classpath/gnu/xml/xpath/NormalizeSpaceFunction.java
new file mode 100644
index 000000000..6d728d9e7
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NormalizeSpaceFunction.java
@@ -0,0 +1,108 @@
+/* NormalizeSpaceFunction.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.xpath;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.util.List;
+import java.util.StringTokenizer;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>normalize-space</code> function returns the argument string
+ * with whitespace normalized by stripping leading and trailing whitespace
+ * and replacing sequences of whitespace characters by a single space.
+ * Whitespace characters are the same as those allowed by the S production
+ * in XML. If the argument is omitted, it defaults to the context node
+ * converted to a string, in other words the string-value of the context
+ * node.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NormalizeSpaceFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ NormalizeSpaceFunction(List<Expr> args)
+ {
+ this(args.get(0));
+ }
+
+ NormalizeSpaceFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = (arg == null) ? null : arg.evaluate(context, pos, len);
+ String s = _string(context, val);
+ StringTokenizer st = new StringTokenizer(s, " \t\r\n");
+ CPStringBuilder buf = new CPStringBuilder();
+ if (st.hasMoreTokens())
+ {
+ buf.append(st.nextToken());
+ while (st.hasMoreTokens())
+ {
+ buf.append(' ');
+ buf.append(st.nextToken());
+ }
+ }
+ return buf.toString();
+ }
+
+ public Expr clone(Object context)
+ {
+ return new NormalizeSpaceFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg == null) ? false : arg.references(var);
+ }
+
+ public String toString()
+ {
+ return (arg == null) ? "normalize-space()" : "normalize-space(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NotFunction.java b/libjava/classpath/gnu/xml/xpath/NotFunction.java
new file mode 100644
index 000000000..a7c20a0c1
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NotFunction.java
@@ -0,0 +1,88 @@
+/* NotFunction.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.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>not</code> function returns true if its argument is false,
+ * and false otherwise.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NotFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ NotFunction(List<Expr> args)
+ {
+ this(args.get(0));
+ }
+
+ NotFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ return _boolean(context, val) ? Boolean.FALSE : Boolean.TRUE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new NotFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "not(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/NumberFunction.java b/libjava/classpath/gnu/xml/xpath/NumberFunction.java
new file mode 100644
index 000000000..08831020b
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/NumberFunction.java
@@ -0,0 +1,103 @@
+/* NumberFunction.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.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>number</code> function converts its argument to a number as
+ * follows:
+ * <ul>
+ * <li>a string that consists of optional whitespace followed by an optional
+ * minus sign followed by a Number followed by whitespace is converted to
+ * the IEEE 754 number that is nearest (according to the IEEE 754
+ * round-to-nearest rule) to the mathematical value represented by the
+ * string; any other string is converted to NaN</li>
+ * <li>boolean true is converted to 1; boolean false is converted to 0</li>
+ * <li>a node-set is first converted to a string as if by a call to the
+ * string function and then converted in the same way as a string
+ * argument</li>
+ * <li>an object of a type other than the four basic types is converted to a
+ * number in a way that is dependent on that type</li>
+ * </ul>
+ * If the argument is omitted, it defaults to a node-set with the context
+ * node as its only member.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class NumberFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ NumberFunction(List<Expr> args)
+ {
+ this(args.size() > 0 ? args.get(0) : null);
+ }
+
+ NumberFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = (arg == null) ? null : arg.evaluate(context, pos, len);
+ return new Double(_number(context, val));
+ }
+
+ public Expr clone(Object context)
+ {
+ return new NumberFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "number(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/OrExpr.java b/libjava/classpath/gnu/xml/xpath/OrExpr.java
new file mode 100644
index 000000000..937dedf6a
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/OrExpr.java
@@ -0,0 +1,87 @@
+/* OrExpr.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.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Logical or.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class OrExpr
+ extends Expr
+{
+
+ final Expr lhs;
+ final Expr rhs;
+
+ public OrExpr(Expr lhs, Expr rhs)
+ {
+ this.lhs = lhs;
+ this.rhs = rhs;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object left = lhs.evaluate(context, pos, len);
+ if (_boolean(context, left))
+ {
+ return Boolean.TRUE;
+ }
+ Object right = rhs.evaluate(context, pos, len);
+ return _boolean(context, right) ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new OrExpr(lhs.clone(context), rhs.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (lhs.references(var) || rhs.references(var));
+ }
+
+ public String toString()
+ {
+ return lhs + " or " + rhs;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/ParenthesizedExpr.java b/libjava/classpath/gnu/xml/xpath/ParenthesizedExpr.java
new file mode 100644
index 000000000..e8ceb5aa5
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/ParenthesizedExpr.java
@@ -0,0 +1,95 @@
+/* ParenthesizedExpr.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.xpath;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Simple subexpression.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class ParenthesizedExpr
+ extends Expr
+{
+
+ final Expr expr;
+
+ ParenthesizedExpr(Expr expr)
+ {
+ this.expr = expr;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object ret = expr.evaluate(context, pos, len);
+ if (ret instanceof Collection)
+ {
+ /* Suppression is safe, as we know context produces
+ Collection<Node> */
+ @SuppressWarnings("unchecked")
+ Collection<Node> nodes = (Collection<Node>) ret;
+ List<Node> list = new ArrayList<Node>(nodes);
+ Collections.sort(list, documentOrderComparator);
+ ret = list;
+ }
+ return ret;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new ParenthesizedExpr(expr.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return expr.references(var);
+ }
+
+ public String toString()
+ {
+ return "(" + expr + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Path.java b/libjava/classpath/gnu/xml/xpath/Path.java
new file mode 100644
index 000000000..f19759567
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Path.java
@@ -0,0 +1,54 @@
+/* Path.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.xpath;
+
+import java.util.Collection;
+import org.w3c.dom.Node;
+
+/**
+ * An XPath path component expression.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+abstract class Path
+ extends Pattern
+{
+
+ abstract Collection<Node> evaluate(Node context, Collection<Node> nodeSet);
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Pattern.java b/libjava/classpath/gnu/xml/xpath/Pattern.java
new file mode 100644
index 000000000..ca03cda37
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Pattern.java
@@ -0,0 +1,53 @@
+/* Pattern.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.xpath;
+
+import org.w3c.dom.Node;
+
+/**
+ * Interface implemented by expressions that can form part of XSL patterns.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public abstract class Pattern
+ extends Expr
+{
+
+ public abstract boolean matches(Node context);
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/PositionFunction.java b/libjava/classpath/gnu/xml/xpath/PositionFunction.java
new file mode 100644
index 000000000..28ead3af0
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/PositionFunction.java
@@ -0,0 +1,73 @@
+/* PositionFunction.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.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>position</code> function returns a number equal to the context
+ * position from the expression evaluation context.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class PositionFunction
+ extends Expr
+{
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ return new Double((double) pos);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new PositionFunction();
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ return "position()";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Predicate.java b/libjava/classpath/gnu/xml/xpath/Predicate.java
new file mode 100644
index 000000000..a02e22b94
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Predicate.java
@@ -0,0 +1,85 @@
+/* Predicate.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.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Tests whether an expression matches against a given context node.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+class Predicate
+ extends Test
+{
+
+ final Expr expr;
+
+ Predicate(Expr expr)
+ {
+ this.expr = expr;
+ }
+
+ public boolean matches(Node node, int pos, int len)
+ {
+ Object ret = expr.evaluate(node, pos, len);
+ if (ret instanceof Double)
+ {
+ // Same as [position() = x]
+ return ((Double) ret).intValue() == pos;
+ }
+ return Expr._boolean(node, expr.evaluate(node, pos, len));
+ }
+
+ public Test clone(Object context)
+ {
+ return new Predicate(expr.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return expr.references(var);
+ }
+
+ public String toString()
+ {
+ return "[" + expr + "]";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/RelationalExpr.java b/libjava/classpath/gnu/xml/xpath/RelationalExpr.java
new file mode 100644
index 000000000..ac79d5049
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/RelationalExpr.java
@@ -0,0 +1,107 @@
+/* RelationalExpr.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.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * Numerical comparison expression.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class RelationalExpr
+ extends Expr
+{
+
+ final Expr lhs;
+ final Expr rhs;
+ final boolean lt;
+ final boolean eq;
+
+ RelationalExpr(Expr lhs, Expr rhs, boolean lt, boolean eq)
+ {
+ this.lhs = lhs;
+ this.rhs = rhs;
+ this.lt = lt;
+ this.eq = eq;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object left = lhs.evaluate(context, pos, len);
+ Object right = rhs.evaluate(context, pos, len);
+ double ln = _number(context, left);
+ double rn = _number(context, right);
+ if (eq && ln == rn)
+ {
+ return Boolean.TRUE;
+ }
+ if (lt)
+ {
+ if (ln < rn || Double.isInfinite(rn))
+ {
+ return Boolean.TRUE;
+ }
+ }
+ else
+ {
+ if (ln > rn || Double.isInfinite(ln))
+ {
+ return Boolean.TRUE;
+ }
+ }
+ return Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new RelationalExpr(lhs.clone(context), rhs.clone(context), lt, eq);
+ }
+
+ public boolean references(QName var)
+ {
+ return (lhs.references(var) || rhs.references(var));
+ }
+
+ public String toString()
+ {
+ return lhs + " " + (lt ? "<" : ">") + (eq ? "=" : "") + " " + rhs;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Root.java b/libjava/classpath/gnu/xml/xpath/Root.java
new file mode 100644
index 000000000..8eef3408f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Root.java
@@ -0,0 +1,91 @@
+/* Root.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.xpath;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+
+/**
+ * Expression that evaluates to the document root.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class Root
+ extends Path
+{
+
+ public boolean matches(Node node)
+ {
+ return (node.getNodeType() == Node.DOCUMENT_NODE);
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Set<Node> emptySet = Collections.emptySet();
+ return evaluate(context, emptySet);
+ }
+
+ @Override
+ Collection<Node> evaluate(Node context, Collection<Node> ns)
+ {
+ Node doc = (context instanceof Document) ? context :
+ context.getOwnerDocument();
+ return Collections.singleton(doc);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new Root();
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ return "/";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/RoundFunction.java b/libjava/classpath/gnu/xml/xpath/RoundFunction.java
new file mode 100644
index 000000000..3b79e3e21
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/RoundFunction.java
@@ -0,0 +1,97 @@
+/* RoundFunction.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.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>round</code> function returns the number that is closest to the
+ * argument and that is an integer. If there are two such numbers, then the
+ * one that is closest to positive infinity is returned. If the argument is
+ * NaN, then NaN is returned. If the argument is positive infinity, then
+ * positive infinity is returned. If the argument is negative infinity, then
+ * negative infinity is returned. If the argument is positive zero, then
+ * positive zero is returned. If the argument is negative zero, then
+ * negative zero is returned. If the argument is less than zero, but greater
+ * than or equal to -0.5, then negative zero is returned.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class RoundFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ RoundFunction(List<Expr> args)
+ {
+ this(args.get(0));
+ }
+
+ RoundFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ double n = _number(context, val);
+ return (Double.isNaN(n) || Double.isInfinite(n)) ?
+ new Double(n) : new Double(Math.round(n));
+ }
+
+ public Expr clone(Object context)
+ {
+ return new RoundFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "round(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Selector.java b/libjava/classpath/gnu/xml/xpath/Selector.java
new file mode 100644
index 000000000..2146f26f5
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Selector.java
@@ -0,0 +1,503 @@
+/* Selector.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.xpath;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+import javax.xml.XMLConstants;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Attr;
+import org.w3c.dom.NamedNodeMap;
+import org.w3c.dom.Node;
+
+/**
+ * A single component of a location path.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class Selector
+ extends Path
+{
+
+ public static final int ANCESTOR = 0;
+ public static final int ANCESTOR_OR_SELF = 1;
+ public static final int ATTRIBUTE = 2;
+ public static final int CHILD = 3;
+ public static final int DESCENDANT = 4;
+ public static final int DESCENDANT_OR_SELF = 5;
+ public static final int FOLLOWING = 6;
+ public static final int FOLLOWING_SIBLING = 7;
+ public static final int NAMESPACE = 8;
+ public static final int PARENT = 9;
+ public static final int PRECEDING = 10;
+ public static final int PRECEDING_SIBLING = 11;
+ public static final int SELF = 12;
+
+ /**
+ * Axis to select nodes in.
+ */
+ final int axis;
+
+ /**
+ * List of tests to perform on candidates.
+ */
+ final Test[] tests;
+
+ public Selector(int axis, List<? extends Test> tests)
+ {
+ this.axis = axis;
+ int len = tests.size();
+ this.tests = new Test[(len == 0) ? 1 : len];
+ if (len > 0)
+ tests.toArray(this.tests);
+ else
+ this.tests[0] = new NodeTypeTest((short) 0);
+ if (axis == NAMESPACE && this.tests[0] instanceof NameTest)
+ {
+ NameTest nt = (NameTest) this.tests[0];
+ this.tests[0] = new NamespaceTest(nt.qName, nt.anyLocalName, nt.any);
+ }
+ }
+
+ /**
+ * Returns the list of tests to perform on candidates.
+ */
+ public Test[] getTests()
+ {
+ return tests;
+ }
+
+ public boolean matches(Node context)
+ {
+ // If called directly, selector is the top level of the path
+ return matches(context,
+ getContextPosition(context),
+ getContextSize(context));
+ }
+
+ boolean matches(Node context, int pos, int len)
+ {
+ short nodeType = context.getNodeType();
+ switch (axis)
+ {
+ case CHILD:
+ if (nodeType == Node.ATTRIBUTE_NODE)
+ return false;
+ break;
+ case ATTRIBUTE:
+ case NAMESPACE:
+ if (nodeType != Node.ATTRIBUTE_NODE)
+ return false;
+ break;
+ case DESCENDANT_OR_SELF:
+ return true;
+ default:
+ return false;
+ }
+ for (int j = 0; j < tests.length && len > 0; j++)
+ {
+ Test test = tests[j];
+ if (!test.matches(context, pos, len))
+ return false;
+ }
+ return true;
+ }
+
+ private int getContextPosition(Node ctx)
+ {
+ int pos = 1;
+ for (ctx = ctx.getPreviousSibling(); ctx != null;
+ ctx = ctx.getPreviousSibling())
+ {
+ if (tests[0].matches(ctx, 1, 1))
+ pos++;
+ }
+ return pos;
+ }
+
+ private int getContextSize(Node ctx)
+ {
+ if (ctx.getNodeType() == Node.ATTRIBUTE_NODE)
+ {
+ Node owner = ((Attr) ctx).getOwnerElement();
+ return owner.getAttributes().getLength();
+ }
+ int count = 1;
+ Node sib = ctx.getPreviousSibling();
+ for (; sib != null; sib = sib.getPreviousSibling())
+ {
+ if (tests[0].matches(ctx, 1, 1))
+ count++;
+ }
+ sib = ctx.getNextSibling();
+ for (; sib != null; sib = sib.getNextSibling())
+ {
+ if (tests[0].matches(ctx, 1, 1))
+ count++;
+ }
+ return count;
+ }
+
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Set<Node> acc = new LinkedHashSet<Node>();
+ addCandidates(context, acc);
+ List<Node> candidates = new ArrayList<Node>(acc);
+ List<Node> ret = filterCandidates(candidates, false);
+ return ret;
+ }
+
+ Collection<Node> evaluate(Node context, Collection<Node> ns)
+ {
+ Set<Node> acc = new LinkedHashSet<Node>();
+ for (Iterator<Node> i = ns.iterator(); i.hasNext(); )
+ addCandidates(i.next(), acc);
+ List<Node> candidates = new ArrayList<Node>(acc);
+ List<Node> ret = filterCandidates(candidates, true);
+ return ret;
+ }
+
+ /**
+ * Filter the given list of candidates according to the node tests.
+ */
+ List<Node> filterCandidates(List<Node> candidates, boolean cascade)
+ {
+ int len = candidates.size();
+ int tlen = tests.length;
+ if (tlen > 0 && len > 0)
+ {
+ // Present the result of each successful generation to the next test
+ for (int j = 0; j < tlen && len > 0; j++)
+ {
+ Test test = tests[j];
+ List<Node> successful = new ArrayList<Node>(len);
+ for (int i = 0; i < len; i++)
+ {
+ Node node = candidates.get(i);
+ if (cascade)
+ {
+ // Documents and DocumentFragments should be considered
+ // if part of a location path where the axis involves
+ // the SELF concept
+ short nodeType = node.getNodeType();
+ if ((nodeType == Node.DOCUMENT_NODE ||
+ nodeType == Node.DOCUMENT_FRAGMENT_NODE) &&
+ (axis == DESCENDANT_OR_SELF ||
+ axis == ANCESTOR_OR_SELF ||
+ axis == SELF) &&
+ (tests.length == 1 &&
+ tests[0] instanceof NodeTypeTest &&
+ ((NodeTypeTest) tests[0]).type == (short) 0))
+ {
+ successful.add(node);
+ continue;
+ }
+ }
+ if (test.matches(node, i + 1, len))
+ successful.add(node);
+ }
+ candidates = successful;
+ len = candidates.size();
+ }
+ }
+ return candidates;
+ }
+
+ void addCandidates(Node context, Collection<Node> candidates)
+ {
+ // Build list of candidates
+ switch (axis)
+ {
+ case CHILD:
+ addChildNodes(context, candidates, false);
+ break;
+ case DESCENDANT:
+ addChildNodes(context, candidates, true);
+ break;
+ case DESCENDANT_OR_SELF:
+ candidates.add (context);
+ addChildNodes(context, candidates, true);
+ break;
+ case PARENT:
+ addParentNode(context, candidates, false);
+ break;
+ case ANCESTOR:
+ addParentNode(context, candidates, true);
+ break;
+ case ANCESTOR_OR_SELF:
+ candidates.add(context);
+ addParentNode(context, candidates, true);
+ break;
+ case FOLLOWING_SIBLING:
+ addFollowingNodes(context, candidates, false);
+ break;
+ case PRECEDING_SIBLING:
+ addPrecedingNodes(context, candidates, false);
+ break;
+ case FOLLOWING:
+ addFollowingNodes(context, candidates, true);
+ break;
+ case PRECEDING:
+ addPrecedingNodes(context, candidates, true);
+ break;
+ case ATTRIBUTE:
+ addAttributes(context, candidates);
+ break;
+ case NAMESPACE:
+ addNamespaceAttributes(context, candidates);
+ break;
+ case SELF:
+ candidates.add(context);
+ break;
+ }
+ }
+
+ void addChildNodes(Node context, Collection<Node> acc, boolean recurse)
+ {
+ Node child = context.getFirstChild();
+ while (child != null)
+ {
+ acc.add(child);
+ if (recurse)
+ addChildNodes(child, acc, recurse);
+ child = child.getNextSibling();
+ }
+ }
+
+ void addParentNode(Node context, Collection<Node> acc, boolean recurse)
+ {
+ Node parent = (context.getNodeType() == Node.ATTRIBUTE_NODE) ?
+ ((Attr) context).getOwnerElement() : context.getParentNode();
+ if (parent != null)
+ {
+ acc.add(parent);
+ if (recurse)
+ addParentNode(parent, acc, recurse);
+ }
+ }
+
+ void addFollowingNodes(Node context, Collection<Node> acc, boolean recurse)
+ {
+ if (context != null && recurse)
+ addChildNodes(context, acc, true);
+ Node cur = (context.getNodeType() == Node.ATTRIBUTE_NODE) ? null :
+ context.getNextSibling();
+ while (cur != null)
+ {
+ acc.add(cur);
+ if (recurse)
+ addChildNodes(cur, acc, true);
+ cur = cur.getNextSibling();
+ }
+ if (recurse)
+ {
+ while (context != null)
+ {
+ context = (context.getNodeType() == Node.ATTRIBUTE_NODE) ?
+ ((Attr) context).getOwnerElement() : context.getParentNode();
+ if (context != null)
+ {
+ cur = context.getNextSibling();
+ while (cur != null)
+ {
+ acc.add(cur);
+ if (recurse)
+ addChildNodes(cur, acc, true);
+ cur = cur.getNextSibling();
+ }
+ }
+ }
+ }
+ }
+
+ void addPrecedingNodes(Node context, Collection<Node> acc, boolean recurse)
+ {
+ Node cur = (context.getNodeType() == Node.ATTRIBUTE_NODE) ? null :
+ context.getPreviousSibling();
+ while (cur != null)
+ {
+ acc.add(cur);
+ if (recurse)
+ addChildNodes(cur, acc, true);
+ cur = cur.getPreviousSibling();
+ }
+ if (recurse)
+ {
+ cur = context;
+ cur = (cur.getNodeType() == Node.ATTRIBUTE_NODE) ?
+ ((Attr) cur).getOwnerElement() : cur.getParentNode();
+ if (cur != null)
+ addPrecedingNodes(cur, acc, recurse);
+ }
+ }
+
+ void addAttributes(Node context, Collection<Node> acc)
+ {
+ NamedNodeMap attrs = context.getAttributes();
+ if (attrs != null)
+ {
+ int attrLen = attrs.getLength();
+ for (int i = 0; i < attrLen; i++)
+ {
+ Node attr = attrs.item(i);
+ if (!isNamespaceAttribute(attr))
+ {
+ acc.add(attr);
+ }
+ }
+ }
+ }
+
+ void addNamespaceAttributes(Node context, Collection<Node> acc)
+ {
+ NamedNodeMap attrs = context.getAttributes();
+ if (attrs != null)
+ {
+ int attrLen = attrs.getLength();
+ for (int i = 0; i < attrLen; i++)
+ {
+ Node attr = attrs.item(i);
+ if (isNamespaceAttribute(attr))
+ acc.add(attr);
+ }
+ }
+ }
+
+ final boolean isNamespaceAttribute(Node node)
+ {
+ String uri = node.getNamespaceURI();
+ return (XMLConstants.XMLNS_ATTRIBUTE_NS_URI.equals(uri) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(node.getPrefix()) ||
+ XMLConstants.XMLNS_ATTRIBUTE.equals(node.getNodeName()));
+ }
+
+ public Expr clone(Object context)
+ {
+ int len = tests.length;
+ List<Test> tests2 = new ArrayList<Test>(len);
+ for (int i = 0; i < len; i++)
+ tests2.add(tests[i].clone(context));
+ return new Selector(axis, tests2);
+ }
+
+ public boolean references(QName var)
+ {
+ for (int i = 0; i < tests.length; i++)
+ {
+ if (tests[i].references(var))
+ return true;
+ }
+ return false;
+ }
+
+ public String toString()
+ {
+ CPStringBuilder buf = new CPStringBuilder();
+ switch (axis)
+ {
+ case ANCESTOR:
+ buf.append("ancestor::");
+ break;
+ case ANCESTOR_OR_SELF:
+ buf.append("ancestor-or-self::");
+ break;
+ case ATTRIBUTE:
+ if (tests.length == 0 ||
+ (tests[0] instanceof NameTest))
+ buf.append('@');
+ else
+ buf.append("attribute::");
+ break;
+ case CHILD:
+ //buf.append("child::");
+ break;
+ case DESCENDANT:
+ buf.append("descendant::");
+ break;
+ case DESCENDANT_OR_SELF:
+ buf.append("descendant-or-self::");
+ break;
+ case FOLLOWING:
+ buf.append("following::");
+ break;
+ case FOLLOWING_SIBLING:
+ buf.append("following-sibling::");
+ break;
+ case NAMESPACE:
+ buf.append("namespace::");
+ break;
+ case PARENT:
+ if (tests.length == 0 ||
+ (tests[0] instanceof NodeTypeTest &&
+ ((NodeTypeTest) tests[0]).type == 0))
+ return "..";
+ buf.append("parent::");
+ break;
+ case PRECEDING:
+ buf.append("preceding::");
+ break;
+ case PRECEDING_SIBLING:
+ buf.append("preceding-sibling::");
+ break;
+ case SELF:
+ if (tests.length == 0 ||
+ (tests[0] instanceof NodeTypeTest &&
+ ((NodeTypeTest) tests[0]).type == 0))
+ return ".";
+ buf.append("self::");
+ break;
+ }
+ if (tests.length == 0)
+ buf.append("[error]");
+ else
+ {
+ for (int i = 0; i < tests.length; i++)
+ buf.append(tests[i]);
+ }
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/StartsWithFunction.java b/libjava/classpath/gnu/xml/xpath/StartsWithFunction.java
new file mode 100644
index 000000000..6f9716a2d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/StartsWithFunction.java
@@ -0,0 +1,92 @@
+/* StartsWithFunction.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.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>starts-with</code> function returns true if the first argument
+ * string starts with the second argument string, and otherwise returns false.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class StartsWithFunction
+ extends Expr
+{
+
+ final Expr arg1;
+ final Expr arg2;
+
+ StartsWithFunction(List<Expr> args)
+ {
+ this(args.get(0), args.get(1));
+ }
+
+ StartsWithFunction(Expr arg1, Expr arg2)
+ {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val1 = arg1.evaluate(context, pos, len);
+ Object val2 = arg2.evaluate(context, pos, len);
+ String s1 = _string(context, val1);
+ String s2 = _string(context, val2);
+ return s1.startsWith(s2) ? Boolean.TRUE : Boolean.FALSE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new StartsWithFunction(arg1.clone(context), arg2.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg1.references(var) || arg2.references(var));
+ }
+
+ public String toString()
+ {
+ return "starts-with(" + arg1 + "," + arg2 + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Steps.java b/libjava/classpath/gnu/xml/xpath/Steps.java
new file mode 100644
index 000000000..75644541c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Steps.java
@@ -0,0 +1,260 @@
+/* Steps.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.xpath;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.LinkedList;
+import java.util.Set;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Attr;
+import org.w3c.dom.Node;
+
+/**
+ * A list of transitions between components in a location path.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class Steps
+ extends Path
+{
+
+ final LinkedList<Expr> path;
+
+ public Steps()
+ {
+ this(new LinkedList<Expr>());
+ }
+
+ Steps(LinkedList<Expr> path)
+ {
+ this.path = path;
+ }
+
+ public boolean matches(Node context)
+ {
+ // Right to left
+ return matches(context, path.size() - 1);
+ }
+
+ boolean matches(Node context, int pos)
+ {
+ Pattern right = (Pattern) path.get(pos);
+ if (!right.matches(context))
+ {
+ return false;
+ }
+ if (pos > 0)
+ {
+ Pattern left = (Pattern) path.get(pos - 1);
+ for (Node candidate : possibleContexts(right, context))
+ {
+ if (left.matches(candidate) &&
+ matches(candidate, pos - 1))
+ {
+ return true;
+ }
+ // keep going, there may be another candidate
+ }
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * Essentially the reverse of Selector.addCandidates.
+ * The idea is to determine possible context nodes for a match.
+ */
+ Collection<Node> possibleContexts(Pattern pattern, Node context)
+ {
+ if (pattern instanceof Selector)
+ {
+ Selector s = (Selector) pattern;
+ Collection<Node> candidates = new LinkedHashSet<Node>();
+ switch (s.axis)
+ {
+ case Selector.PARENT:
+ s.addChildNodes(context, candidates, false);
+ break;
+ case Selector.ANCESTOR:
+ s.addChildNodes(context, candidates, true);
+ break;
+ case Selector.ANCESTOR_OR_SELF:
+ candidates.add (context);
+ s.addChildNodes(context, candidates, true);
+ break;
+ case Selector.CHILD:
+ s.addParentNode(context, candidates, false);
+ break;
+ case Selector.DESCENDANT:
+ s.addParentNode(context, candidates, true);
+ break;
+ case Selector.DESCENDANT_OR_SELF:
+ candidates.add(context);
+ s.addParentNode(context, candidates, true);
+ break;
+ case Selector.PRECEDING_SIBLING:
+ s.addFollowingNodes(context, candidates, false);
+ break;
+ case Selector.FOLLOWING_SIBLING:
+ s.addPrecedingNodes(context, candidates, false);
+ break;
+ case Selector.PRECEDING:
+ s.addFollowingNodes(context, candidates, true);
+ break;
+ case Selector.FOLLOWING:
+ s.addPrecedingNodes(context, candidates, true);
+ break;
+ case Selector.ATTRIBUTE:
+ case Selector.NAMESPACE:
+ if (context.getNodeType() == Node.ATTRIBUTE_NODE)
+ {
+ candidates.add(((Attr) context).getOwnerElement());
+ }
+ break;
+ case Selector.SELF:
+ candidates.add(context);
+ break;
+ }
+ return candidates;
+ }
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ //System.err.println(toString()+" evaluate");
+ // Left to right
+ Iterator<Expr> i = path.iterator();
+ Expr lhs = i.next();
+ Object val = lhs.evaluate(context, pos, len);
+ //System.err.println("\tevaluate "+lhs+" = "+val);
+ while (val instanceof Collection && i.hasNext())
+ {
+ Path rhs = (Path) i.next();
+ /* Suppression is safe, as we know context produces Collection<Node> */
+ @SuppressWarnings("unchecked")
+ Collection<Node> nodes = (Collection<Node>) val;
+ val = rhs.evaluate(context, nodes);
+ //System.err.println("\tevaluate "+rhs+" = "+val);
+ }
+ return val;
+ }
+
+ @Override
+ Collection<Node> evaluate(Node context, Collection<Node> ns)
+ {
+ // Left to right
+ Iterator<Expr> i = path.iterator();
+ Expr lhs = i.next();
+ if (lhs instanceof Path)
+ {
+ ns = ((Path) lhs).evaluate(context, ns);
+ }
+ else
+ {
+ Set<Node> acc = new LinkedHashSet<Node>();
+ int pos = 1, len = ns.size();
+ for (Node node : ns)
+ {
+ Object ret = lhs.evaluate(node, pos++, len);
+ if (ret instanceof Collection)
+ {
+ /* Suppression is safe, as we know context produces Collection<Node> */
+ @SuppressWarnings("unchecked")
+ Collection<Node> nodes = (Collection<Node>) ret;
+ acc.addAll(nodes);
+ }
+ }
+ ns = acc;
+ }
+ while (i.hasNext())
+ {
+ Path rhs = (Path) i.next();
+ ns = rhs.evaluate(context, ns);
+ }
+ return ns;
+ }
+
+ public Expr clone(Object context)
+ {
+ int len = path.size();
+ LinkedList<Expr> path2 = new LinkedList<Expr>();
+ for (int i = 0; i < len; i++)
+ {
+ path2.add(path.get(i).clone(context));
+ }
+ return new Steps(path2);
+ }
+
+ public boolean references(QName var)
+ {
+ for (Iterator<Expr> i = path.iterator(); i.hasNext(); )
+ {
+ if (i.next().references(var))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public String toString()
+ {
+ CPStringBuilder buf = new CPStringBuilder();
+ Iterator<Expr> i = path.iterator();
+ Expr expr = i.next();
+ if (!(expr instanceof Root))
+ {
+ buf.append(expr);
+ }
+ while (i.hasNext())
+ {
+ expr = i.next();
+ buf.append('/');
+ buf.append(expr);
+ }
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/StringFunction.java b/libjava/classpath/gnu/xml/xpath/StringFunction.java
new file mode 100644
index 000000000..b2b3cecf7
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/StringFunction.java
@@ -0,0 +1,119 @@
+/* StringFunction.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.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>string function converts an object to a string as follows:
+ * <ul>
+ * <li>A node-set is converted to a string by returning the string-value of
+ * the node in the node-set that is first in document order. If the node-set
+ * is empty, an empty string is returned.</li>
+ * <li>A number is converted to a string as follows
+ * <ul>
+ * <li>NaN is converted to the string NaN</li>
+ * <li>positive zero is converted to the string 0</li>
+ * <li>negative zero is converted to the string 0</li>
+ * <li>positive infinity is converted to the string Infinity</li>
+ * <li>negative infinity is converted to the string -Infinity</li>
+ * <li>if the number is an integer, the number is represented in decimal
+ * form as a Number with no decimal point and no leading zeros, preceded by
+ * a minus sign (-) if the number is negative</li>
+ * <li>otherwise, the number is represented in decimal form as a Number
+ * including a decimal point with at least one digit before the decimal
+ * point and at least one digit after the decimal point, preceded by a minus
+ * sign (-) if the number is negative; there must be no leading zeros before
+ * the decimal point apart possibly from the one required digit immediately
+ * before the decimal point; beyond the one required digit after the decimal
+ * point there must be as many, but only as many, more digits as are needed
+ * to uniquely distinguish the number from all other IEEE 754 numeric
+ * values.</li>
+ * </ul>
+ * </li>
+ * <li>The boolean false value is converted to the string false. The boolean
+ * true value is converted to the string true.</li>
+ * <li>An object of a type other than the four basic types is converted to a
+ * string in a way that is dependent on that type.</li>
+ * </ul>
+ * If the argument is omitted, it defaults to a node-set with the context
+ * node as its only member.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class StringFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ StringFunction(List<Expr> args)
+ {
+ this(args.size() > 0 ? args.get(0) : null);
+ }
+
+ StringFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = (arg == null) ? null : arg.evaluate(context, pos, len);
+ return _string(context, val);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new StringFunction((arg == null) ? null :
+ arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg == null) ? false : arg.references(var);
+ }
+
+ public String toString()
+ {
+ return (arg == null) ? "string()" : "string(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/StringLengthFunction.java b/libjava/classpath/gnu/xml/xpath/StringLengthFunction.java
new file mode 100644
index 000000000..c72b0d9bc
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/StringLengthFunction.java
@@ -0,0 +1,92 @@
+/* StringLengthFunction.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.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>string-length</code> function returns the number of characters
+ * in the string.
+ * If the argument is omitted, it defaults to the context node converted to
+ * a string, in other words the string-value of the context node.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class StringLengthFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ StringLengthFunction(List<Expr> args)
+ {
+ this(args.isEmpty() ? null : (Expr) args.get(0));
+ }
+
+ StringLengthFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = (arg == null) ? null : arg.evaluate(context, pos, len);
+ String s = _string(context, val);
+ return new Double((double) s.length());
+ }
+
+ public Expr clone(Object context)
+ {
+ return new StringLengthFunction((arg == null) ? null :
+ arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg == null) ? false : arg.references(var);
+ }
+
+ public String toString()
+ {
+ return (arg == null) ? "string-length()" : "string-length(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/SubstringAfterFunction.java b/libjava/classpath/gnu/xml/xpath/SubstringAfterFunction.java
new file mode 100644
index 000000000..4f10723a7
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/SubstringAfterFunction.java
@@ -0,0 +1,98 @@
+/* SubstringAfterFunction.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.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>substring-after</code> function returns the substring of the
+ * first argument string that follows the first occurrence of the second
+ * argument string in the first argument string, or the empty string if the
+ * first argument string does not contain the second argument string. For
+ * example, substring-after("1999/04/01","/") returns 04/01, and
+ * substring-after("1999/04/01","19") returns 99/04/01.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class SubstringAfterFunction
+ extends Expr
+{
+
+ final Expr arg1;
+ final Expr arg2;
+
+ SubstringAfterFunction(List<Expr> args)
+ {
+ this(args.get(0), args.get(1));
+ }
+
+ SubstringAfterFunction(Expr arg1, Expr arg2)
+ {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val1 = arg1.evaluate(context, pos, len);
+ Object val2 = arg2.evaluate(context, pos, len);
+ String s1 = _string(context, val1);
+ String s2 = _string(context, val2);
+ int index = s1.indexOf(s2);
+ return (index == -1) ? "" : s1.substring(index + s2.length());
+ }
+
+ public Expr clone(Object context)
+ {
+ return new SubstringAfterFunction(arg1.clone(context),
+ arg2.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg1.references(var) || arg2.references(var));
+ }
+
+ public String toString()
+ {
+ return "substring-after(" + arg1 + "," + arg2 + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/SubstringBeforeFunction.java b/libjava/classpath/gnu/xml/xpath/SubstringBeforeFunction.java
new file mode 100644
index 000000000..1a5a04c4f
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/SubstringBeforeFunction.java
@@ -0,0 +1,97 @@
+/* SubstringBeforeFunction.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.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>substring-before</code> function returns the substring of the
+ * first argument string that precedes the first occurrence of the second
+ * argument string in the first argument string, or the empty string if the
+ * first argument string does not contain the second argument string. For
+ * example, substring-before("1999/04/01","/") returns 1999.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class SubstringBeforeFunction
+ extends Expr
+{
+
+ final Expr arg1;
+ final Expr arg2;
+
+ SubstringBeforeFunction(List<Expr> args)
+ {
+ this(args.get(0), args.get(1));
+ }
+
+ SubstringBeforeFunction(Expr arg1, Expr arg2)
+ {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val1 = arg1.evaluate(context, pos, len);
+ Object val2 = arg2.evaluate(context, pos, len);
+ String s1 = _string(context, val1);
+ String s2 = _string(context, val2);
+ int index = s1.indexOf(s2);
+ return (index == -1) ? "" : s1.substring(0, index);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new SubstringBeforeFunction(arg1.clone(context),
+ arg2.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg1.references(var) || arg2.references(var));
+ }
+
+ public String toString()
+ {
+ return "substring-before(" + arg1 + "," + arg2 + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/SubstringFunction.java b/libjava/classpath/gnu/xml/xpath/SubstringFunction.java
new file mode 100644
index 000000000..d17c3b662
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/SubstringFunction.java
@@ -0,0 +1,119 @@
+/* SubstringFunction.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.xpath;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The substring function returns the substring of the first argument
+ * starting at the position specified in the second argument with length
+ * specified in the third argument. For example, substring("12345",2,3)
+ * returns "234". If the third argument is not specified, it returns the
+ * substring starting at the position specified in the second argument and
+ * continuing to the end of the string. For example, substring("12345",2)
+ * returns "2345".
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class SubstringFunction
+ extends Expr
+{
+
+ final Expr arg1;
+ final Expr arg2;
+ final Expr arg3;
+
+ SubstringFunction(List<Expr> args)
+ {
+ this(args.get(0), args.get(1),
+ (args.size() > 2) ? args.get(2) : null);
+ }
+
+ SubstringFunction(Expr arg1, Expr arg2, Expr arg3)
+ {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ this.arg3 = arg3;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val1 = arg1.evaluate(context, pos, len);
+ Object val2 = arg2.evaluate(context, pos, len);
+ String s = _string(context, val1);
+ int p = Expr.intValue(val2) - 1;
+ if (p < 0)
+ p = 0;
+
+ int l = s.length() - p;
+ if (l <= 0)
+ return "";
+
+ if (arg3 != null)
+ {
+ Object val3 = arg3.evaluate(context, pos, len);
+ int v3 = Expr.intValue(val3);
+ if (v3 < l)
+ l = v3;
+ }
+
+ return s.substring(p, p + l);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new SubstringFunction(arg1.clone(context), arg2.clone(context),
+ (arg3 == null) ? null : arg3.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg1.references(var) || arg2.references(var) ||
+ (arg3 == null) ? false : arg3.references(var));
+ }
+
+ public String toString()
+ {
+ return (arg3 == null) ? "substring(" + arg1 + "," + arg2 + ")" :
+ "substring(" + arg1 + "," + arg2 + "," + arg3 + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/SumFunction.java b/libjava/classpath/gnu/xml/xpath/SumFunction.java
new file mode 100644
index 000000000..6c3323fb2
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/SumFunction.java
@@ -0,0 +1,104 @@
+/* SumFunction.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.xpath;
+
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>sum</code> function returns the sum, for each node in the
+ * argument node-set, of the result of converting the string-values of the
+ * node to a number.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class SumFunction
+ extends Expr
+{
+
+ final Expr arg;
+
+ SumFunction(List<Expr> args)
+ {
+ this(args.get(0));
+ }
+
+ SumFunction(Expr arg)
+ {
+ this.arg = arg;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val = arg.evaluate(context, pos, len);
+ double sum = 0.0d;
+ if (val instanceof Collection)
+ {
+ /* Suppression is safe, as we know context produces
+ Collection<Node> */
+ @SuppressWarnings("unchecked")
+ Collection<Node> nodes = (Collection<Node>) val;
+ for (Node node : nodes)
+ {
+ String s = stringValue(node);
+ sum += _number(context, s);
+ }
+ }
+ return new Double(sum);
+ }
+
+ public Expr clone(Object context)
+ {
+ return new SumFunction(arg.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return arg.references(var);
+ }
+
+ public String toString()
+ {
+ return "sum(" + arg + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/Test.java b/libjava/classpath/gnu/xml/xpath/Test.java
new file mode 100644
index 000000000..529c99bd8
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/Test.java
@@ -0,0 +1,58 @@
+/* Test.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.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * A test that can be performed on a node to determine whether to include it
+ * in a selection.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public abstract class Test
+{
+
+ public abstract boolean matches(Node node, int pos, int len);
+
+ public abstract Test clone(Object context);
+
+ public abstract boolean references(QName var);
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/TranslateFunction.java b/libjava/classpath/gnu/xml/xpath/TranslateFunction.java
new file mode 100644
index 000000000..4e06354c3
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/TranslateFunction.java
@@ -0,0 +1,135 @@
+/* TranslateFunction.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.xpath;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.util.List;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>translate</code> function returns the first argument string
+ * with occurrences of characters in the second argument string replaced by
+ * the character at the corresponding position in the third argument string.
+ * For example, translate("bar","abc","ABC") returns the string BAr. If
+ * there is a character in the second argument string with no character at a
+ * corresponding position in the third argument string (because the second
+ * argument string is longer than the third argument string), then
+ * occurrences of that character in the first argument string are removed.
+ * For example, translate("--aaa--","abc-","ABC") returns "AAA". If a
+ * character occurs more than once in the second argument string, then the
+ * first occurrence determines the replacement character. If the third
+ * argument string is longer than the second argument string, then excess
+ * characters are ignored.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class TranslateFunction
+ extends Expr
+{
+
+ final Expr arg1;
+ final Expr arg2;
+ final Expr arg3;
+
+ TranslateFunction(List<Expr> args)
+ {
+ this(args.get(0), args.get(1), args.get(2));
+ }
+
+ TranslateFunction(Expr arg1, Expr arg2, Expr arg3)
+ {
+ this.arg1 = arg1;
+ this.arg2 = arg2;
+ this.arg3 = arg3;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object val1 = arg1.evaluate(context, pos, len);
+ Object val2 = arg2.evaluate(context, pos, len);
+ Object val3 = arg3.evaluate(context, pos, len);
+ String string = _string(context, val1);
+ String search = _string(context, val2);
+ String replace = _string(context, val3);
+ CPStringBuilder buf = new CPStringBuilder();
+ int l1 = string.length();
+ int l2 = search.length();
+ int l3 = replace.length();
+ for (int i = 0; i < l1; i++)
+ {
+ char c = string.charAt(i);
+ boolean replaced = false;
+ for (int j = 0; j < l2; j++)
+ {
+ if (c == search.charAt(j))
+ {
+ if (j < l3)
+ {
+ buf.append(replace.charAt(j));
+ }
+ replaced = true;
+ }
+ }
+ if (!replaced)
+ {
+ buf.append(c);
+ }
+ }
+ return buf.toString();
+ }
+
+ public Expr clone(Object context)
+ {
+ return new TranslateFunction(arg1.clone(context), arg2.clone(context),
+ arg3.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (arg1.references(var) || arg2.references(var) ||
+ arg3.references(var));
+ }
+
+ public String toString()
+ {
+ return "translate(" + arg1 + "," + arg2 + "," + arg3 + ")";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/TrueFunction.java b/libjava/classpath/gnu/xml/xpath/TrueFunction.java
new file mode 100644
index 000000000..41ab54b75
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/TrueFunction.java
@@ -0,0 +1,72 @@
+/* TrueFunction.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.xpath;
+
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The <code>true</code> function returns true.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+final class TrueFunction
+ extends Expr
+{
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ return Boolean.TRUE;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new TrueFunction();
+ }
+
+ public boolean references(QName var)
+ {
+ return false;
+ }
+
+ public String toString()
+ {
+ return "true()";
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/UnionExpr.java b/libjava/classpath/gnu/xml/xpath/UnionExpr.java
new file mode 100644
index 000000000..bd5f5e990
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/UnionExpr.java
@@ -0,0 +1,117 @@
+/* UnionExpr.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.xpath;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.xml.namespace.QName;
+import org.w3c.dom.Node;
+
+/**
+ * The union of two node-sets.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public final class UnionExpr
+ extends Pattern
+{
+
+ final Expr lhs;
+ final Expr rhs;
+
+ public UnionExpr(Expr lhs, Expr rhs)
+ {
+ this.lhs = lhs;
+ this.rhs = rhs;
+ }
+
+ public boolean matches(Node context)
+ {
+ if (lhs instanceof Pattern && rhs instanceof Pattern)
+ {
+ return ((Pattern) lhs).matches(context) ||
+ ((Pattern) rhs).matches(context);
+ }
+ return false;
+ }
+
+ @Override
+ public Object evaluate(Node context, int pos, int len)
+ {
+ Object left = lhs.evaluate(context, pos, len);
+ Object right = rhs.evaluate(context, pos, len);
+ List<Node> list;
+ if (left instanceof Collection && right instanceof Collection)
+ {
+ Set<Node> set = new HashSet<Node>();
+ /* Suppression is safe as addAll will check the types
+ of the elements and throw a ClassCastException as necessary */
+ @SuppressWarnings("unchecked")
+ Collection<Node> l = (Collection<Node>) left;
+ @SuppressWarnings("unchecked")
+ Collection<Node> r = (Collection<Node>) right;
+ set.addAll (l);
+ set.addAll (r);
+ list = new ArrayList<Node>(set);
+ Collections.sort(list, documentOrderComparator);
+ }
+ else
+ list = Collections.emptyList();
+ return list;
+ }
+
+ public Expr clone(Object context)
+ {
+ return new UnionExpr(lhs.clone(context), rhs.clone(context));
+ }
+
+ public boolean references(QName var)
+ {
+ return (lhs.references(var) || rhs.references(var));
+ }
+
+ public String toString()
+ {
+ return lhs + " | " + rhs;
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/VariableReference.java b/libjava/classpath/gnu/xml/xpath/VariableReference.java
new file mode 100644
index 000000000..e1698c94c
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/VariableReference.java
@@ -0,0 +1,102 @@
+/* VariableReference.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.xpath;
+
+import gnu.java.lang.CPStringBuilder;
+
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathVariableResolver;
+import org.w3c.dom.Node;
+import gnu.xml.transform.Bindings;
+
+public class VariableReference
+ extends Expr
+{
+
+ final XPathVariableResolver resolver;
+ final QName name;
+
+ public VariableReference(XPathVariableResolver resolver, QName name)
+ {
+ this.resolver = resolver;
+ this.name = name;
+ }
+
+ public Object evaluate(Node context, int pos, int len)
+ {
+ if (resolver != null)
+ {
+ if (resolver instanceof Bindings)
+ {
+ // Needs context to operate properly
+ return ((Bindings) resolver).get(name, context, pos, len);
+ }
+ return resolver.resolveVariable(name);
+ }
+ throw new IllegalStateException("no variable resolver");
+ }
+
+ public Expr clone(Object context)
+ {
+ XPathVariableResolver r = resolver;
+ if (context instanceof XPathVariableResolver)
+ {
+ r = (XPathVariableResolver) context;
+ }
+ return new VariableReference(r, name);
+ }
+
+ public boolean references(QName var)
+ {
+ return name.equals(var);
+ }
+
+ public String toString()
+ {
+ CPStringBuilder buf = new CPStringBuilder("$");
+ String prefix = name.getPrefix();
+ if (prefix != null && !"".equals(prefix))
+ {
+ buf.append(prefix);
+ buf.append(':');
+ }
+ buf.append(name.getLocalPart());
+ return buf.toString();
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/XPathFactoryImpl.java b/libjava/classpath/gnu/xml/xpath/XPathFactoryImpl.java
new file mode 100644
index 000000000..970cf0e5d
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/XPathFactoryImpl.java
@@ -0,0 +1,90 @@
+/* XPathFactoryImpl.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.xpath;
+
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathFactory;
+import javax.xml.xpath.XPathFactoryConfigurationException;
+import javax.xml.xpath.XPathFunctionResolver;
+import javax.xml.xpath.XPathVariableResolver;
+
+/**
+ * GNU XPath factory implementation.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class XPathFactoryImpl
+ extends XPathFactory
+{
+
+ XPathVariableResolver variableResolver;
+ XPathFunctionResolver functionResolver;
+
+ public boolean isObjectModelSupported(String objectModel)
+ {
+ return XPathFactory.DEFAULT_OBJECT_MODEL_URI.equals(objectModel);
+ }
+
+ public void setFeature(String name, boolean value)
+ throws XPathFactoryConfigurationException
+ {
+ throw new XPathFactoryConfigurationException(name);
+ }
+
+ public boolean getFeature(String name)
+ throws XPathFactoryConfigurationException
+ {
+ throw new XPathFactoryConfigurationException(name);
+ }
+
+ public void setXPathVariableResolver(XPathVariableResolver resolver)
+ {
+ variableResolver = resolver;
+ }
+
+ public void setXPathFunctionResolver(XPathFunctionResolver resolver)
+ {
+ functionResolver = resolver;
+ }
+
+ public XPath newXPath()
+ {
+ return new XPathImpl(null, variableResolver, functionResolver);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/XPathImpl.java b/libjava/classpath/gnu/xml/xpath/XPathImpl.java
new file mode 100644
index 000000000..62f86171b
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/XPathImpl.java
@@ -0,0 +1,164 @@
+/* XPathImpl.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.xpath;
+
+import java.io.IOException;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPathFunctionResolver;
+import javax.xml.xpath.XPathVariableResolver;
+import org.xml.sax.InputSource;
+
+/**
+ * JAXP XPath implementation.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class XPathImpl
+ implements XPath
+{
+
+ XPathParser parser;
+ NamespaceContext namespaceContext;
+ XPathVariableResolver variableResolver;
+ XPathFunctionResolver functionResolver;
+
+ XPathImpl(NamespaceContext namespaceContext,
+ XPathVariableResolver variableResolver,
+ XPathFunctionResolver functionResolver)
+ {
+ parser = new XPathParser();
+ this.namespaceContext = namespaceContext;
+ this.variableResolver = variableResolver;
+ this.functionResolver = functionResolver;
+ reset();
+ }
+
+ public void reset()
+ {
+ parser.namespaceContext = namespaceContext;
+ parser.variableResolver = variableResolver;
+ parser.functionResolver = functionResolver;
+ }
+
+ public void setXPathVariableResolver(XPathVariableResolver resolver)
+ {
+ parser.variableResolver = resolver;
+ }
+
+ public XPathVariableResolver getXPathVariableResolver()
+ {
+ return parser.variableResolver;
+ }
+
+ public void setXPathFunctionResolver(XPathFunctionResolver resolver)
+ {
+ parser.functionResolver = resolver;
+ }
+
+ public XPathFunctionResolver getXPathFunctionResolver()
+ {
+ return parser.functionResolver;
+ }
+
+ public void setNamespaceContext(NamespaceContext nsContext)
+ {
+ parser.namespaceContext = nsContext;
+ }
+
+ public NamespaceContext getNamespaceContext()
+ {
+ return parser.namespaceContext;
+ }
+
+ public XPathExpression compile(String expression)
+ throws XPathExpressionException
+ {
+ XPathTokenizer tokenizer = new XPathTokenizer(expression);
+ try
+ {
+ return (Expr) parser.yyparse(tokenizer);
+ }
+ catch (IOException e)
+ {
+ throw new XPathExpressionException(e);
+ }
+ catch (XPathParser.yyException e)
+ {
+ throw new XPathExpressionException(expression);
+ }
+ }
+
+ public Object evaluate(String expression,
+ Object item,
+ QName returnType)
+ throws XPathExpressionException
+ {
+ XPathExpression expr = compile(expression);
+ return expr.evaluate(item, returnType);
+ }
+
+ public String evaluate(String expression,
+ Object item)
+ throws XPathExpressionException
+ {
+ XPathExpression expr = compile(expression);
+ return expr.evaluate(item);
+ }
+
+ public Object evaluate(String expression,
+ InputSource source,
+ QName returnType)
+ throws XPathExpressionException
+ {
+ XPathExpression expr = compile(expression);
+ return expr.evaluate(source, returnType);
+ }
+
+ public String evaluate(String expression,
+ InputSource source)
+ throws XPathExpressionException
+ {
+ XPathExpression expr = compile(expression);
+ return expr.evaluate(source);
+ }
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/XPathParser.java b/libjava/classpath/gnu/xml/xpath/XPathParser.java
new file mode 100644
index 000000000..26e59091e
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/XPathParser.java
@@ -0,0 +1,1475 @@
+// created by jay 0.8 (c) 1998 Axel.Schreiner@informatik.uni-osnabrueck.de
+
+ // line 2 "XPathParser.y"
+/* XPathParser.y - An XPath 1.0 parser.
+ Copyright (C) 2004 The 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.xml.xpath;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunctionResolver;
+import javax.xml.xpath.XPathVariableResolver;
+import org.w3c.dom.Node;
+
+/**
+ * An XPath 1.0 parser.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class XPathParser
+{
+
+ NamespaceContext namespaceContext;
+ XPathVariableResolver variableResolver;
+ XPathFunctionResolver functionResolver;
+
+ QName getQName(String name)
+ {
+ QName qName = QName.valueOf(name);
+ if (namespaceContext != null)
+ {
+ String prefix = qName.getPrefix();
+ String uri = qName.getNamespaceURI();
+ if (prefix != null && (uri == null || uri.length() == 0))
+ {
+ uri = namespaceContext.getNamespaceURI(prefix);
+ String localName = qName.getLocalPart();
+ qName = new QName(uri, localName, prefix);
+ }
+ }
+ return qName;
+ }
+
+ Expr lookupFunction(String name, List<Expr> args)
+ {
+ int arity = args.size();
+ if ("position".equals(name) && arity == 0)
+ {
+ return new PositionFunction();
+ }
+ else if ("last".equals(name) && arity == 0)
+ {
+ return new LastFunction();
+ }
+ else if ("string".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new StringFunction(args);
+ }
+ else if ("number".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NumberFunction(args);
+ }
+ else if ("boolean".equals(name) && arity == 1)
+ {
+ return new BooleanFunction(args);
+ }
+ else if ("count".equals(name) && arity == 1)
+ {
+ return new CountFunction(args);
+ }
+ else if ("not".equals(name) && arity == 1)
+ {
+ return new NotFunction(args);
+ }
+ else if ("id".equals(name) && arity == 1)
+ {
+ return new IdFunction(args);
+ }
+ else if ("concat".equals(name) && arity > 1)
+ {
+ return new ConcatFunction(args);
+ }
+ else if ("true".equals(name) && arity == 0)
+ {
+ return new TrueFunction();
+ }
+ else if ("false".equals(name) && arity == 0)
+ {
+ return new FalseFunction();
+ }
+ else if ("name".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NameFunction(args);
+ }
+ else if ("local-name".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new LocalNameFunction(args);
+ }
+ else if ("namespace-uri".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NamespaceUriFunction(args);
+ }
+ else if ("starts-with".equals(name) && arity == 2)
+ {
+ return new StartsWithFunction(args);
+ }
+ else if ("contains".equals(name) && arity == 2)
+ {
+ return new ContainsFunction(args);
+ }
+ else if ("string-length".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new StringLengthFunction(args);
+ }
+ else if ("translate".equals(name) && arity == 3)
+ {
+ return new TranslateFunction(args);
+ }
+ else if ("normalize-space".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NormalizeSpaceFunction(args);
+ }
+ else if ("substring".equals(name) && (arity == 2 || arity == 3))
+ {
+ return new SubstringFunction(args);
+ }
+ else if ("substring-before".equals(name) && arity == 2)
+ {
+ return new SubstringBeforeFunction(args);
+ }
+ else if ("substring-after".equals(name) && arity == 2)
+ {
+ return new SubstringAfterFunction(args);
+ }
+ else if ("lang".equals(name) && arity == 1)
+ {
+ return new LangFunction(args);
+ }
+ else if ("sum".equals(name) && arity == 1)
+ {
+ return new SumFunction(args);
+ }
+ else if ("floor".equals(name) && arity == 1)
+ {
+ return new FloorFunction(args);
+ }
+ else if ("ceiling".equals(name) && arity == 1)
+ {
+ return new CeilingFunction(args);
+ }
+ else if ("round".equals(name) && arity == 1)
+ {
+ return new RoundFunction(args);
+ }
+ else if (functionResolver != null)
+ {
+ QName qName = QName.valueOf(name);
+ Object function = functionResolver.resolveFunction(qName, arity);
+ if (function != null &&
+ function instanceof Function &&
+ function instanceof Expr)
+ {
+ Function f = (Function) function;
+ f.setArguments(args);
+ return (Expr) function;
+ }
+ }
+ return new FunctionCall(functionResolver, name, args);
+ }
+
+ // line 211 "-"
+// %token constants
+
+ public static final int LITERAL = 257;
+ public static final int DIGITS = 258;
+ public static final int NAME = 259;
+ public static final int LP = 260;
+ public static final int RP = 261;
+ public static final int LB = 262;
+ public static final int RB = 263;
+ public static final int COMMA = 264;
+ public static final int PIPE = 265;
+ public static final int SLASH = 266;
+ public static final int DOUBLE_SLASH = 267;
+ public static final int EQ = 268;
+ public static final int NE = 269;
+ public static final int GT = 270;
+ public static final int LT = 271;
+ public static final int GTE = 272;
+ public static final int LTE = 273;
+ public static final int PLUS = 274;
+ public static final int MINUS = 275;
+ public static final int AT = 276;
+ public static final int STAR = 277;
+ public static final int DOLLAR = 278;
+ public static final int COLON = 279;
+ public static final int DOUBLE_COLON = 280;
+ public static final int DOT = 281;
+ public static final int DOUBLE_DOT = 282;
+ public static final int ANCESTOR = 283;
+ public static final int ANCESTOR_OR_SELF = 284;
+ public static final int ATTRIBUTE = 285;
+ public static final int CHILD = 286;
+ public static final int DESCENDANT = 287;
+ public static final int DESCENDANT_OR_SELF = 288;
+ public static final int FOLLOWING = 289;
+ public static final int FOLLOWING_SIBLING = 290;
+ public static final int NAMESPACE = 291;
+ public static final int PARENT = 292;
+ public static final int PRECEDING = 293;
+ public static final int PRECEDING_SIBLING = 294;
+ public static final int SELF = 295;
+ public static final int DIV = 296;
+ public static final int MOD = 297;
+ public static final int OR = 298;
+ public static final int AND = 299;
+ public static final int COMMENT = 300;
+ public static final int PROCESSING_INSTRUCTION = 301;
+ public static final int TEXT = 302;
+ public static final int NODE = 303;
+ public static final int UNARY = 304;
+ public static final int yyErrorCode = 256;
+
+ /** thrown for irrecoverable syntax errors and stack overflow.
+ */
+ public static class yyException extends java.lang.Exception {
+ public yyException (String message) {
+ super(message);
+ }
+ }
+
+ /** must be implemented by a scanner object to supply input to the parser.
+ */
+ public interface yyInput {
+ /** move on to next token.
+ @return false if positioned beyond tokens.
+ @throws IOException on input error.
+ */
+ boolean advance () throws java.io.IOException;
+ /** classifies current token.
+ Should not be called if advance() returned false.
+ @return current %token or single character.
+ */
+ int token ();
+ /** associated with current token.
+ Should not be called if advance() returned false.
+ @return value for token().
+ */
+ Object value ();
+ }
+
+ /** simplified error message.
+ @see <a href="#yyerror(java.lang.String, java.lang.String[])">yyerror</a>
+ */
+ public void yyerror (String message) {
+ yyerror(message, null);
+ }
+
+ /** (syntax) error message.
+ Can be overwritten to control message format.
+ @param message text to be displayed.
+ @param expected vector of acceptable tokens, if available.
+ */
+ public void yyerror (String message, String[] expected) {
+ if (expected != null && expected.length > 0) {
+ System.err.print(message+", expecting");
+ for (int n = 0; n < expected.length; ++ n)
+ System.err.print(" "+expected[n]);
+ System.err.println();
+ } else
+ System.err.println(message);
+ }
+
+ /** debugging support, requires the package jay.yydebug.
+ Set to null to suppress debugging messages.
+ */
+//t protected jay.yydebug.yyDebug yydebug;
+
+ protected static final int yyFinal = 30;
+
+ /** index-checked interface to yyName[].
+ @param token single character or %token value.
+ @return token name or [illegal] or [unknown].
+ */
+//t public static final String yyname (int token) {
+//t if (token < 0 || token > YyNameClass.yyName.length) return "[illegal]";
+//t String name;
+//t if ((name = YyNameClass.yyName[token]) != null) return name;
+//t return "[unknown]";
+//t }
+
+ /** computes list of expected tokens on error by tracing the tables.
+ @param state for which to compute the list.
+ @return list of token names.
+ */
+ protected String[] yyExpecting (int state) {
+ int token, n, len = 0;
+ boolean[] ok = new boolean[YyNameClass.yyName.length];
+
+ if ((n = YySindexClass.yySindex[state]) != 0)
+ for (token = n < 0 ? -n : 0;
+ token < YyNameClass.yyName.length && n+token < YyTableClass.yyTable.length; ++ token)
+ if (YyCheckClass.yyCheck[n+token] == token && !ok[token] && YyNameClass.yyName[token] != null) {
+ ++ len;
+ ok[token] = true;
+ }
+ if ((n = YyRindexClass.yyRindex[state]) != 0)
+ for (token = n < 0 ? -n : 0;
+ token < YyNameClass.yyName.length && n+token < YyTableClass.yyTable.length; ++ token)
+ if (YyCheckClass.yyCheck[n+token] == token && !ok[token] && YyNameClass.yyName[token] != null) {
+ ++ len;
+ ok[token] = true;
+ }
+
+ String result[] = new String[len];
+ for (n = token = 0; n < len; ++ token)
+ if (ok[token]) result[n++] = YyNameClass.yyName[token];
+ return result;
+ }
+
+ /** the generated parser, with debugging messages.
+ Maintains a state and a value stack, currently with fixed maximum size.
+ @param yyLex scanner.
+ @param yydebug debug message writer implementing yyDebug, or null.
+ @return result of the last reduction, if any.
+ @throws yyException on irrecoverable parse error.
+ */
+ public Object yyparse (yyInput yyLex, Object yydebug)
+ throws java.io.IOException, yyException {
+//t this.yydebug = (jay.yydebug.yyDebug)yydebug;
+ return yyparse(yyLex);
+ }
+
+ /** initial size and increment of the state/value stack [default 256].
+ This is not final so that it can be overwritten outside of invocations
+ of yyparse().
+ */
+ protected int yyMax;
+
+ /** executed at the beginning of a reduce action.
+ Used as $$ = yyDefault($1), prior to the user-specified action, if any.
+ Can be overwritten to provide deep copy, etc.
+ @param first value for $1, or null.
+ @return first.
+ */
+ protected Object yyDefault (Object first) {
+ return first;
+ }
+
+ /** the generated parser.
+ Maintains a state and a value stack, currently with fixed maximum size.
+ @param yyLex scanner.
+ @return result of the last reduction, if any.
+ @throws yyException on irrecoverable parse error.
+ */
+ public Object yyparse (yyInput yyLex)
+ throws java.io.IOException, yyException {
+ if (yyMax <= 0) yyMax = 256; // initial size
+ int yyState = 0, yyStates[] = new int[yyMax]; // state stack
+ Object yyVal = null, yyVals[] = new Object[yyMax]; // value stack
+ int yyToken = -1; // current input
+ int yyErrorFlag = 0; // #tks to shift
+
+ yyLoop: for (int yyTop = 0;; ++ yyTop) {
+ if (yyTop >= yyStates.length) { // dynamically increase
+ int[] i = new int[yyStates.length+yyMax];
+ System.arraycopy(yyStates, 0, i, 0, yyStates.length);
+ yyStates = i;
+ Object[] o = new Object[yyVals.length+yyMax];
+ System.arraycopy(yyVals, 0, o, 0, yyVals.length);
+ yyVals = o;
+ }
+ yyStates[yyTop] = yyState;
+ yyVals[yyTop] = yyVal;
+//t if (yydebug != null) yydebug.push(yyState, yyVal);
+
+ yyDiscarded: for (;;) { // discarding a token does not change stack
+ int yyN;
+ if ((yyN = YyDefRedClass.yyDefRed[yyState]) == 0) { // else [default] reduce (yyN)
+ if (yyToken < 0) {
+ yyToken = yyLex.advance() ? yyLex.token() : 0;
+//t if (yydebug != null)
+//t yydebug.lex(yyState, yyToken, yyname(yyToken), yyLex.value());
+ }
+ if ((yyN = YySindexClass.yySindex[yyState]) != 0 && (yyN += yyToken) >= 0
+ && yyN < YyTableClass.yyTable.length && YyCheckClass.yyCheck[yyN] == yyToken) {
+//t if (yydebug != null)
+//t yydebug.shift(yyState, YyTableClass.yyTable[yyN], yyErrorFlag-1);
+ yyState = YyTableClass.yyTable[yyN]; // shift to yyN
+ yyVal = yyLex.value();
+ yyToken = -1;
+ if (yyErrorFlag > 0) -- yyErrorFlag;
+ continue yyLoop;
+ }
+ if ((yyN = YyRindexClass.yyRindex[yyState]) != 0 && (yyN += yyToken) >= 0
+ && yyN < YyTableClass.yyTable.length && YyCheckClass.yyCheck[yyN] == yyToken)
+ yyN = YyTableClass.yyTable[yyN]; // reduce (yyN)
+ else
+ switch (yyErrorFlag) {
+
+ case 0:
+ yyerror("syntax error", yyExpecting(yyState));
+//t if (yydebug != null) yydebug.error("syntax error");
+
+ case 1: case 2:
+ yyErrorFlag = 3;
+ do {
+ if ((yyN = YySindexClass.yySindex[yyStates[yyTop]]) != 0
+ && (yyN += yyErrorCode) >= 0 && yyN < YyTableClass.yyTable.length
+ && YyCheckClass.yyCheck[yyN] == yyErrorCode) {
+//t if (yydebug != null)
+//t yydebug.shift(yyStates[yyTop], YyTableClass.yyTable[yyN], 3);
+ yyState = YyTableClass.yyTable[yyN];
+ yyVal = yyLex.value();
+ continue yyLoop;
+ }
+//t if (yydebug != null) yydebug.pop(yyStates[yyTop]);
+ } while (-- yyTop >= 0);
+//t if (yydebug != null) yydebug.reject();
+ throw new yyException("irrecoverable syntax error");
+
+ case 3:
+ if (yyToken == 0) {
+//t if (yydebug != null) yydebug.reject();
+ throw new yyException("irrecoverable syntax error at end-of-file");
+ }
+//t if (yydebug != null)
+//t yydebug.discard(yyState, yyToken, yyname(yyToken),
+//t yyLex.value());
+ yyToken = -1;
+ continue yyDiscarded; // leave stack alone
+ }
+ }
+ int yyV = yyTop + 1-YyLenClass.yyLen[yyN];
+//t if (yydebug != null)
+//t yydebug.reduce(yyState, yyStates[yyV-1], yyN, YyRuleClass.yyRule[yyN], YyLenClass.yyLen[yyN]);
+ yyVal = yyDefault(yyV > yyTop ? null : yyVals[yyV]);
+ switch (yyN) {
+case 4:
+ // line 277 "XPathParser.y"
+ {
+ yyVal = new Root();
+ }
+ break;
+case 5:
+ // line 281 "XPathParser.y"
+ {
+ Steps steps;
+ if (yyVals[0+yyTop] instanceof Steps)
+ {
+ steps = (Steps) yyVals[0+yyTop];
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst((Expr) yyVals[0+yyTop]);
+ }
+ steps.path.addFirst(new Root());
+ yyVal = steps;
+ /*$$ = new Step(new Root(), (Path) $2);*/
+ }
+ break;
+case 6:
+ // line 297 "XPathParser.y"
+ {
+ Test nt = new NodeTypeTest((short) 0);
+ Selector s = new Selector(Selector.DESCENDANT_OR_SELF,
+ Collections.singletonList (nt));
+ Steps steps;
+ if (yyVals[0+yyTop] instanceof Steps)
+ {
+ steps = (Steps) yyVals[0+yyTop];
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst((Expr) yyVals[0+yyTop]);
+ }
+ steps.path.addFirst(s);
+ steps.path.addFirst(new Root());
+ yyVal = steps;
+ /*Step step = new Step(s, (Path) $2);*/
+ /*$$ = new Step(new Root(), step);*/
+ }
+ break;
+case 8:
+ // line 322 "XPathParser.y"
+ {
+ Steps steps;
+ if (yyVals[-2+yyTop] instanceof Steps)
+ {
+ steps = (Steps) yyVals[-2+yyTop];
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst((Expr) yyVals[-2+yyTop]);
+ }
+ steps.path.addLast((Expr) yyVals[0+yyTop]);
+ yyVal = steps;
+ /*$$ = new Step((Expr) $1, (Path) $3);*/
+ }
+ break;
+case 9:
+ // line 338 "XPathParser.y"
+ {
+ Test nt = new NodeTypeTest((short) 0);
+ Selector s = new Selector(Selector.DESCENDANT_OR_SELF,
+ Collections.singletonList (nt));
+ Steps steps;
+ if (yyVals[-2+yyTop] instanceof Steps)
+ {
+ steps = (Steps) yyVals[-2+yyTop];
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst((Expr) yyVals[-2+yyTop]);
+ }
+ steps.path.addLast(s);
+ steps.path.addLast((Expr) yyVals[0+yyTop]);
+ yyVal = steps;
+ /*Step step = new Step(s, (Path) $3);*/
+ /*$$ = new Step((Expr) $1, step);*/
+ }
+ break;
+case 10:
+ // line 362 "XPathParser.y"
+ {
+ @SuppressWarnings("unchecked") List<Test> tests = (List<Test>) yyVals[0+yyTop];
+ yyVal = new Selector (Selector.CHILD, tests);
+ }
+ break;
+case 11:
+ // line 366 "XPathParser.y"
+ {
+ /* This is safe as we create this in one of the other cases */
+ @SuppressWarnings("unchecked") List<Test> tests = (List<Test>) yyVals[0+yyTop];
+ yyVal = new Selector (Selector.ATTRIBUTE, tests);
+ }
+ break;
+case 12:
+ // line 370 "XPathParser.y"
+ {
+ /* This is safe as we create this in one of the other cases */
+ @SuppressWarnings("unchecked") List<Test> tests = (List<Test>) yyVals[0+yyTop];
+ yyVal = new Selector (((Integer) yyVals[-2+yyTop]).intValue (), tests);
+ }
+ break;
+case 13:
+ // line 374 "XPathParser.y"
+ {
+ List<Test> emptyList = Collections.emptyList();
+ yyVal = new Selector (Selector.SELF, emptyList);
+ }
+ break;
+case 14:
+ // line 378 "XPathParser.y"
+ {
+ List<Test> emptyList = Collections.emptyList();
+ yyVal = new Selector (Selector.PARENT, emptyList);
+ }
+ break;
+case 15:
+ // line 385 "XPathParser.y"
+ {
+ List<Test> list = new ArrayList<Test>();
+ list.add((Test) yyVals[0+yyTop]);
+ yyVal = list;
+ }
+ break;
+case 16:
+ // line 391 "XPathParser.y"
+ {
+ /* This is safe as we create this in one of the other cases */
+ @SuppressWarnings("unchecked") List<Test> tests = (List<Test>)yyVals[-1+yyTop];
+ tests.add((Test) yyVals[0+yyTop]);
+ yyVal = tests;
+ }
+ break;
+case 17:
+ // line 415 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.ANCESTOR);
+ }
+ break;
+case 18:
+ // line 419 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.ANCESTOR_OR_SELF);
+ }
+ break;
+case 19:
+ // line 423 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.ATTRIBUTE);
+ }
+ break;
+case 20:
+ // line 427 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.CHILD);
+ }
+ break;
+case 21:
+ // line 431 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.DESCENDANT);
+ }
+ break;
+case 22:
+ // line 435 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.DESCENDANT_OR_SELF);
+ }
+ break;
+case 23:
+ // line 439 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.FOLLOWING);
+ }
+ break;
+case 24:
+ // line 443 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.FOLLOWING_SIBLING);
+ }
+ break;
+case 25:
+ // line 447 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.NAMESPACE);
+ }
+ break;
+case 26:
+ // line 451 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.PARENT);
+ }
+ break;
+case 27:
+ // line 455 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.PRECEDING);
+ }
+ break;
+case 28:
+ // line 459 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.PRECEDING_SIBLING);
+ }
+ break;
+case 29:
+ // line 463 "XPathParser.y"
+ {
+ yyVal = new Integer(Selector.SELF);
+ }
+ break;
+case 31:
+ // line 472 "XPathParser.y"
+ {
+ yyVal = new NodeTypeTest(Node.PROCESSING_INSTRUCTION_NODE, (String) yyVals[-1+yyTop]);
+ }
+ break;
+case 32:
+ // line 477 "XPathParser.y"
+ {
+ yyVal = new NodeTypeTest(((Short) yyVals[-1+yyTop]).shortValue());
+ }
+ break;
+case 33:
+ // line 484 "XPathParser.y"
+ {
+ yyVal = new Predicate((Expr) yyVals[-1+yyTop]);
+ }
+ break;
+case 35:
+ // line 492 "XPathParser.y"
+ {
+ yyVal = new ParenthesizedExpr((Expr) yyVals[-1+yyTop]);
+ }
+ break;
+case 36:
+ // line 496 "XPathParser.y"
+ {
+ yyVal = new Constant(yyVals[0+yyTop]);
+ }
+ break;
+case 37:
+ // line 500 "XPathParser.y"
+ {
+ yyVal = new Constant(yyVals[0+yyTop]);
+ }
+ break;
+case 39:
+ // line 508 "XPathParser.y"
+ {
+ List<Expr> emptyList = Collections.emptyList();
+ yyVal = lookupFunction((String) yyVals[-2+yyTop], emptyList);
+ }
+ break;
+case 40:
+ // line 512 "XPathParser.y"
+ {
+ /* This is safe as we create this below */
+ @SuppressWarnings("unchecked") List<Expr> exprs = (List<Expr>) yyVals[-1+yyTop];
+ yyVal = lookupFunction((String) yyVals[-3+yyTop], exprs);
+ }
+ break;
+case 41:
+ // line 519 "XPathParser.y"
+ {
+ List<Expr> list = new ArrayList<Expr>();
+ list.add((Expr) yyVals[0+yyTop]);
+ yyVal = list;
+ }
+ break;
+case 42:
+ // line 525 "XPathParser.y"
+ {
+ /* This is safe as we create this above */
+ @SuppressWarnings("unchecked") List<Expr> list = (List<Expr>) yyVals[0+yyTop];
+ list.add(0, (Expr) yyVals[-2+yyTop]);
+ yyVal = list;
+ }
+ break;
+case 44:
+ // line 535 "XPathParser.y"
+ {
+ yyVal = new UnionExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop]);
+ }
+ break;
+case 47:
+ // line 544 "XPathParser.y"
+ {
+ Steps steps;
+ if (yyVals[0+yyTop] instanceof Steps)
+ {
+ steps = (Steps) yyVals[0+yyTop];
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst((Expr) yyVals[0+yyTop]);
+ }
+ steps.path.addFirst((Expr) yyVals[-2+yyTop]);
+ yyVal = steps;
+ /*$$ = new Step ((Expr) $1, (Path) $3);*/
+ }
+ break;
+case 48:
+ // line 560 "XPathParser.y"
+ {
+ Test nt = new NodeTypeTest((short) 0);
+ Selector s = new Selector(Selector.DESCENDANT_OR_SELF,
+ Collections.singletonList(nt));
+ Steps steps;
+ if (yyVals[0+yyTop] instanceof Steps)
+ {
+ steps = (Steps) yyVals[0+yyTop];
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst((Expr) yyVals[0+yyTop]);
+ }
+ steps.path.addFirst(s);
+ steps.path.addFirst((Expr) yyVals[-2+yyTop]);
+ yyVal = steps;
+ /*Step step = new Step (s, (Path) $3);*/
+ /*$$ = new Step ((Expr) $1, step);*/
+ }
+ break;
+case 50:
+ // line 585 "XPathParser.y"
+ {
+ Predicate filter = (Predicate) yyVals[0+yyTop];
+ Selector s = new Selector(Selector.SELF,
+ Collections.singletonList(filter));
+ Steps steps;
+ if (yyVals[-1+yyTop] instanceof Steps)
+ {
+ steps = (Steps) yyVals[-1+yyTop];
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst((Expr) yyVals[-1+yyTop]);
+ }
+ steps.path.addLast(s);
+ yyVal = steps;
+ /*$$ = new Step ((Expr) $1, s);*/
+ }
+ break;
+case 52:
+ // line 608 "XPathParser.y"
+ {
+ yyVal = new OrExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop]);
+ }
+ break;
+case 54:
+ // line 616 "XPathParser.y"
+ {
+ yyVal = new AndExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop]);
+ }
+ break;
+case 56:
+ // line 624 "XPathParser.y"
+ {
+ yyVal = new EqualityExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], false);
+ }
+ break;
+case 57:
+ // line 628 "XPathParser.y"
+ {
+ yyVal = new EqualityExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], true);
+ }
+ break;
+case 59:
+ // line 636 "XPathParser.y"
+ {
+ yyVal = new RelationalExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], true, false);
+ }
+ break;
+case 60:
+ // line 640 "XPathParser.y"
+ {
+ yyVal = new RelationalExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], false, false);
+ }
+ break;
+case 61:
+ // line 644 "XPathParser.y"
+ {
+ yyVal = new RelationalExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], true, true);
+ }
+ break;
+case 62:
+ // line 648 "XPathParser.y"
+ {
+ yyVal = new RelationalExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], false, true);
+ }
+ break;
+case 64:
+ // line 656 "XPathParser.y"
+ {
+ yyVal = new ArithmeticExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], ArithmeticExpr.ADD);
+ }
+ break;
+case 65:
+ // line 660 "XPathParser.y"
+ {
+ yyVal = new ArithmeticExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], ArithmeticExpr.SUBTRACT);
+ }
+ break;
+case 67:
+ // line 668 "XPathParser.y"
+ {
+ yyVal = new ArithmeticExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], ArithmeticExpr.MULTIPLY);
+ }
+ break;
+case 68:
+ // line 672 "XPathParser.y"
+ {
+ yyVal = new ArithmeticExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], ArithmeticExpr.DIVIDE);
+ }
+ break;
+case 69:
+ // line 676 "XPathParser.y"
+ {
+ yyVal = new ArithmeticExpr((Expr) yyVals[-2+yyTop], (Expr) yyVals[0+yyTop], ArithmeticExpr.MODULO);
+ }
+ break;
+case 71:
+ // line 684 "XPathParser.y"
+ {
+ yyVal = new NegativeExpr((Expr) yyVals[0+yyTop]);
+ }
+ break;
+case 72:
+ // line 691 "XPathParser.y"
+ {
+ yyVal = new Double((String) yyVals[0+yyTop] + ".0");
+ }
+ break;
+case 73:
+ // line 695 "XPathParser.y"
+ {
+ yyVal = new Double((String) yyVals[-1+yyTop] + ".0");
+ }
+ break;
+case 74:
+ // line 699 "XPathParser.y"
+ {
+ yyVal = new Double((String) yyVals[-2+yyTop] + "." + (String) yyVals[0+yyTop]);
+ }
+ break;
+case 75:
+ // line 703 "XPathParser.y"
+ {
+ yyVal = new Double("0." + (String) yyVals[0+yyTop]);
+ }
+ break;
+case 77:
+ // line 732 "XPathParser.y"
+ {
+ String name = (String) yyVals[0+yyTop];
+ yyVal = new VariableReference(variableResolver, getQName(name));
+ }
+ break;
+case 78:
+ // line 740 "XPathParser.y"
+ {
+ yyVal = new NameTest(null, true, true);
+ }
+ break;
+case 79:
+ // line 744 "XPathParser.y"
+ {
+ QName qName = getQName((String) yyVals[-2+yyTop]);
+ yyVal = new NameTest(qName, true, false);
+ }
+ break;
+case 80:
+ // line 749 "XPathParser.y"
+ {
+ QName qName = getQName((String) yyVals[0+yyTop]);
+ yyVal = new NameTest(qName, false, false);
+ }
+ break;
+case 82:
+ // line 758 "XPathParser.y"
+ {
+ yyVal = (String) yyVals[-2+yyTop] + ':' + (String) yyVals[0+yyTop];
+ }
+ break;
+case 83:
+ // line 765 "XPathParser.y"
+ {
+ yyVal = new Short(Node.COMMENT_NODE);
+ }
+ break;
+case 84:
+ // line 769 "XPathParser.y"
+ {
+ yyVal = new Short(Node.TEXT_NODE);
+ }
+ break;
+case 85:
+ // line 773 "XPathParser.y"
+ {
+ yyVal = new Short(Node.PROCESSING_INSTRUCTION_NODE);
+ }
+ break;
+case 86:
+ // line 777 "XPathParser.y"
+ {
+ yyVal = new Short((short) 0);
+ }
+ break;
+ // line 988 "-"
+ }
+ yyTop -= YyLenClass.yyLen[yyN];
+ yyState = yyStates[yyTop];
+ int yyM = YyLhsClass.yyLhs[yyN];
+ if (yyState == 0 && yyM == 0) {
+//t if (yydebug != null) yydebug.shift(0, yyFinal);
+ yyState = yyFinal;
+ if (yyToken < 0) {
+ yyToken = yyLex.advance() ? yyLex.token() : 0;
+//t if (yydebug != null)
+//t yydebug.lex(yyState, yyToken,yyname(yyToken), yyLex.value());
+ }
+ if (yyToken == 0) {
+//t if (yydebug != null) yydebug.accept(yyVal);
+ return yyVal;
+ }
+ continue yyLoop;
+ }
+ if ((yyN = YyGindexClass.yyGindex[yyM]) != 0 && (yyN += yyState) >= 0
+ && yyN < YyTableClass.yyTable.length && YyCheckClass.yyCheck[yyN] == yyState)
+ yyState = YyTableClass.yyTable[yyN];
+ else
+ yyState = YyDgotoClass.yyDgoto[yyM];
+//t if (yydebug != null) yydebug.shift(yyStates[yyTop], yyState);
+ continue yyLoop;
+ }
+ }
+ }
+
+ protected static final class YyLhsClass {
+
+ public static final short yyLhs [] = { -1,
+ 0, 2, 2, 4, 4, 4, 3, 3, 3, 5,
+ 5, 5, 5, 5, 6, 6, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 8,
+ 8, 8, 9, 12, 12, 12, 12, 12, 15, 15,
+ 17, 17, 18, 18, 19, 19, 19, 19, 20, 20,
+ 1, 1, 21, 21, 22, 22, 22, 23, 23, 23,
+ 23, 23, 24, 24, 24, 25, 25, 25, 25, 26,
+ 26, 14, 14, 14, 14, 16, 13, 10, 10, 10,
+ 27, 27, 11, 11, 11, 11,
+ };
+ } /* End of class YyLhsClass */
+
+ protected static final class YyLenClass {
+
+ public static final short yyLen [] = { 2,
+ 1, 1, 1, 1, 2, 2, 1, 3, 3, 1,
+ 2, 3, 1, 1, 1, 2, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 3, 2, 3, 1, 3, 1, 1, 1, 3, 4,
+ 1, 3, 1, 3, 1, 1, 3, 3, 1, 2,
+ 1, 3, 1, 3, 1, 3, 3, 1, 3, 3,
+ 3, 3, 1, 3, 3, 1, 3, 3, 3, 1,
+ 2, 1, 2, 3, 2, 1, 2, 1, 3, 1,
+ 1, 3, 1, 1, 1, 1,
+ };
+ } /* End class YyLenClass */
+
+ protected static final class YyDefRedClass {
+
+ public static final short yyDefRed [] = { 0,
+ 36, 0, 0, 0, 0, 0, 0, 0, 78, 0,
+ 0, 14, 17, 18, 19, 20, 21, 22, 23, 24,
+ 25, 26, 27, 28, 29, 83, 0, 84, 86, 0,
+ 0, 45, 0, 3, 7, 0, 0, 15, 30, 0,
+ 49, 34, 37, 38, 0, 0, 43, 0, 0, 0,
+ 0, 0, 0, 66, 0, 0, 0, 0, 13, 0,
+ 80, 0, 71, 0, 0, 77, 75, 0, 0, 0,
+ 0, 0, 16, 0, 32, 0, 0, 0, 0, 50,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 74, 82, 79, 35, 0, 31, 0, 8,
+ 9, 0, 0, 39, 0, 0, 44, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 67, 68,
+ 69, 33, 0, 40, 42,
+ };
+ } /* End of class YyDefRedClass */
+
+ protected static final class YyDgotoClass {
+
+ public static final short yyDgoto [] = { 105,
+ 31, 32, 33, 34, 35, 36, 37, 38, 73, 39,
+ 40, 41, 42, 43, 44, 45, 106, 46, 47, 48,
+ 49, 50, 51, 52, 53, 54, 55,
+ };
+ } /* End of class YyDgotoClass */
+
+ protected static final class YySindexClass {
+
+ public static final short yySindex [] = { -97,
+ 0, -271, -267, -97, -239, -239, -97, -199, 0, -236,
+ -222, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -218, 0, 0, 0,
+ -257, 0, -241, 0, 0, -205, -221, 0, 0, -194,
+ 0, 0, 0, 0, -190, -185, 0, -238, -211, -234,
+ -255, -209, -275, 0, 0, -169, -250, -168, 0, -241,
+ 0, -241, 0, -205, -187, 0, 0, -167, -97, -239,
+ -239, -97, 0, -199, 0, -151, -43, -239, -239, 0,
+ -97, -97, -97, -97, -97, -97, -97, -97, -97, -97,
+ -97, -97, 0, 0, 0, 0, -164, 0, -211, 0,
+ 0, -166, -205, 0, -165, -163, 0, -241, -241, -234,
+ -255, -255, -209, -209, -209, -209, -275, -275, 0, 0,
+ 0, 0, -97, 0, 0,
+ };
+ } /* End of class YySindexClass */
+
+ protected static final class YyRindexClass {
+
+ public static final short yyRindex [] = { 0,
+ 0, 58, 1, 0, 420, 0, 0, 0, 0, 0,
+ 129, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, -161, 0, 0, 0,
+ 40, 0, 237, 0, 0, 168, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 459, 0, 277, 557, 544,
+ 656, 561, 474, 0, 19, 75, 0, 0, 0, 295,
+ 0, 334, 0, 183, 114, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 686, 0,
+ 0, 0, 222, 0, -156, 0, 0, 351, 405, 553,
+ 665, 697, 577, 600, 617, 639, 513, 528, 0, 0,
+ 0, 0, 0, 0, 0,
+ };
+ } /* End of class YyRindexClass */
+
+ protected static final class YyGindexClass {
+
+ public static final short yyGindex [] = { 7,
+ 0, 0, 8, 0, 3, -3, 0, 0, 48, 0,
+ 0, 0, 0, 0, 0, 0, -12, 0, 35, 0,
+ 44, 36, -1, -54, 2, -7, -2,
+ };
+ } /* End of class YyGindexClass */
+
+ protected static final class YyTableClass {
+
+ public static final short yyTable [] = { 63,
+ 81, 90, 61, 61, 64, 61, 30, 66, 94, 56,
+ 58, 57, 60, 62, 84, 85, 86, 87, 80, 3,
+ 91, 92, 65, 72, 70, 71, 95, 78, 79, 113,
+ 114, 115, 116, 82, 83, 67, 8, 9, 68, 1,
+ 69, 59, 12, 13, 14, 15, 16, 17, 18, 19,
+ 20, 21, 22, 23, 24, 25, 72, 72, 74, 3,
+ 26, 27, 28, 29, 88, 89, 75, 61, 61, 76,
+ 103, 61, 100, 101, 73, 61, 61, 9, 102, 77,
+ 111, 112, 119, 120, 121, 108, 109, 81, 93, 117,
+ 118, 97, 96, 98, 94, 80, 122, 124, 123, 85,
+ 26, 27, 28, 29, 41, 1, 2, 3, 4, 104,
+ 125, 107, 99, 81, 5, 6, 110, 0, 0, 0,
+ 0, 0, 0, 7, 8, 9, 10, 0, 13, 11,
+ 12, 13, 14, 15, 16, 17, 18, 19, 20, 21,
+ 22, 23, 24, 25, 0, 0, 0, 0, 26, 27,
+ 28, 29, 0, 0, 0, 0, 0, 0, 0, 1,
+ 2, 3, 4, 0, 0, 0, 0, 10, 5, 6,
+ 0, 0, 0, 0, 0, 0, 0, 7, 8, 9,
+ 10, 0, 11, 11, 12, 13, 14, 15, 16, 17,
+ 18, 19, 20, 21, 22, 23, 24, 25, 0, 0,
+ 0, 0, 26, 27, 28, 29, 0, 0, 0, 0,
+ 0, 0, 0, 1, 2, 3, 4, 0, 0, 0,
+ 0, 12, 5, 6, 0, 0, 0, 0, 0, 0,
+ 0, 0, 8, 9, 10, 0, 2, 11, 12, 13,
+ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
+ 24, 25, 0, 0, 0, 0, 26, 27, 28, 29,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 46, 81, 76, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 5, 80, 81, 81, 81, 81,
+ 1, 0, 1, 1, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 80, 80, 80, 80, 72, 72,
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 72, 72, 6, 72, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 47, 73, 0, 72, 72, 72, 72, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 73, 73, 73, 73, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 13,
+ 81, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 48, 13, 0, 0, 0, 81,
+ 81, 81, 81, 0, 0, 0, 0, 0, 0, 4,
+ 0, 0, 0, 0, 13, 13, 13, 13, 10, 0,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 11, 10, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 70, 11,
+ 0, 0, 0, 10, 10, 10, 10, 0, 0, 0,
+ 0, 0, 0, 63, 0, 0, 0, 0, 11, 11,
+ 11, 11, 12, 0, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 12, 12, 2, 12, 2,
+ 2, 2, 0, 0, 2, 2, 2, 2, 2, 2,
+ 2, 2, 64, 2, 0, 0, 0, 12, 12, 12,
+ 12, 0, 0, 0, 0, 0, 0, 65, 0, 0,
+ 0, 0, 2, 2, 2, 2, 0, 46, 0, 46,
+ 46, 46, 0, 53, 46, 46, 46, 46, 46, 46,
+ 46, 46, 54, 46, 0, 5, 51, 5, 5, 5,
+ 58, 0, 5, 5, 5, 5, 5, 5, 5, 5,
+ 0, 5, 46, 46, 46, 46, 60, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 5, 5, 5, 5, 6, 0, 6, 6, 6, 59,
+ 0, 6, 6, 6, 6, 6, 6, 6, 6, 0,
+ 6, 47, 0, 47, 47, 47, 62, 0, 47, 47,
+ 47, 47, 47, 47, 47, 47, 0, 47, 0, 6,
+ 6, 6, 6, 0, 0, 0, 0, 0, 61, 0,
+ 0, 0, 0, 0, 0, 0, 47, 47, 47, 47,
+ 0, 0, 0, 0, 0, 55, 0, 0, 0, 0,
+ 0, 0, 0, 0, 56, 48, 0, 48, 48, 48,
+ 0, 0, 48, 48, 48, 48, 48, 48, 48, 48,
+ 4, 48, 4, 4, 4, 52, 0, 4, 4, 4,
+ 4, 4, 4, 4, 4, 0, 57, 0, 0, 0,
+ 48, 48, 48, 48, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 4, 4, 4, 4, 70,
+ 0, 70, 70, 0, 0, 0, 70, 70, 70, 70,
+ 70, 70, 70, 70, 63, 70, 63, 63, 0, 0,
+ 0, 63, 63, 63, 63, 63, 63, 63, 63, 0,
+ 0, 0, 0, 0, 70, 70, 70, 70, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 63, 63, 64, 0, 64, 64, 0, 0, 0,
+ 64, 64, 64, 64, 64, 64, 64, 64, 65, 0,
+ 65, 65, 0, 0, 0, 65, 65, 65, 65, 65,
+ 65, 65, 65, 0, 53, 0, 53, 53, 0, 0,
+ 64, 64, 0, 54, 0, 54, 54, 51, 0, 51,
+ 51, 58, 0, 58, 58, 65, 65, 0, 58, 58,
+ 58, 58, 58, 58, 0, 0, 0, 60, 0, 60,
+ 60, 53, 53, 0, 60, 60, 60, 60, 60, 60,
+ 54, 54, 0, 0, 51, 0, 0, 0, 58, 58,
+ 59, 0, 59, 59, 0, 0, 0, 59, 59, 59,
+ 59, 59, 59, 0, 60, 60, 0, 62, 0, 62,
+ 62, 0, 0, 0, 62, 62, 62, 62, 62, 62,
+ 0, 0, 0, 0, 0, 0, 0, 59, 59, 61,
+ 0, 61, 61, 0, 0, 0, 61, 61, 61, 61,
+ 61, 61, 0, 0, 62, 62, 55, 0, 55, 55,
+ 0, 0, 0, 55, 55, 56, 0, 56, 56, 0,
+ 0, 0, 56, 56, 0, 0, 61, 61, 0, 0,
+ 0, 0, 0, 0, 0, 0, 52, 0, 52, 52,
+ 0, 0, 0, 55, 55, 0, 0, 57, 0, 57,
+ 57, 0, 56, 56, 57, 57, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 52, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 57, 57,
+ };
+ } /* End of class YyTableClass */
+
+ protected static final class YyCheckClass {
+
+ public static final short yyCheck [] = { 7,
+ 0, 277, 5, 6, 8, 8, 0, 10, 259, 281,
+ 4, 279, 5, 6, 270, 271, 272, 273, 0, 259,
+ 296, 297, 259, 262, 266, 267, 277, 266, 267, 84,
+ 85, 86, 87, 268, 269, 258, 276, 277, 257, 0,
+ 298, 281, 282, 283, 284, 285, 286, 287, 288, 289,
+ 290, 291, 292, 293, 294, 295, 262, 0, 280, 259,
+ 300, 301, 302, 303, 274, 275, 261, 70, 71, 260,
+ 74, 74, 70, 71, 0, 78, 79, 277, 72, 265,
+ 82, 83, 90, 91, 92, 78, 79, 299, 258, 88,
+ 89, 279, 261, 261, 259, 48, 263, 261, 264, 261,
+ 300, 301, 302, 303, 261, 257, 258, 259, 260, 261,
+ 123, 77, 69, 0, 266, 267, 81, -1, -1, -1,
+ -1, -1, -1, 275, 276, 277, 278, -1, 0, 281,
+ 282, 283, 284, 285, 286, 287, 288, 289, 290, 291,
+ 292, 293, 294, 295, -1, -1, -1, -1, 300, 301,
+ 302, 303, -1, -1, -1, -1, -1, -1, -1, 257,
+ 258, 259, 260, -1, -1, -1, -1, 0, 266, 267,
+ -1, -1, -1, -1, -1, -1, -1, 275, 276, 277,
+ 278, -1, 0, 281, 282, 283, 284, 285, 286, 287,
+ 288, 289, 290, 291, 292, 293, 294, 295, -1, -1,
+ -1, -1, 300, 301, 302, 303, -1, -1, -1, -1,
+ -1, -1, -1, 257, 258, 259, 260, -1, -1, -1,
+ -1, 0, 266, 267, -1, -1, -1, -1, -1, -1,
+ -1, -1, 276, 277, 278, -1, 0, 281, 282, 283,
+ 284, 285, 286, 287, 288, 289, 290, 291, 292, 293,
+ 294, 295, -1, -1, -1, -1, 300, 301, 302, 303,
+ 260, 261, 262, 263, 264, 265, 266, 267, 268, 269,
+ 270, 271, 272, 273, 274, 275, 0, 277, 260, 261,
+ 262, 263, 264, 265, 266, 267, 268, 269, 270, 271,
+ 272, 273, 274, 275, 0, 277, 296, 297, 298, 299,
+ 261, -1, 263, 264, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 296, 297, 298, 299, 261, 262,
+ 263, 264, 265, 266, 267, 268, 269, 270, 271, 272,
+ 273, 274, 275, 0, 277, 261, 262, 263, 264, 265,
+ 266, 267, 268, 269, 270, 271, 272, 273, 274, 275,
+ 0, 277, -1, 296, 297, 298, 299, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 296, 297, 298, 299, 261, 262, 263, 264, 265, 266,
+ 267, 268, 269, 270, 271, 272, 273, 274, 275, 261,
+ 277, 263, 264, 265, 266, 267, 268, 269, 270, 271,
+ 272, 273, 274, 275, 0, 277, -1, -1, -1, 296,
+ 297, 298, 299, -1, -1, -1, -1, -1, -1, 0,
+ -1, -1, -1, -1, 296, 297, 298, 299, 261, -1,
+ 263, 264, 265, 266, 267, 268, 269, 270, 271, 272,
+ 273, 274, 275, 261, 277, 263, 264, 265, 266, 267,
+ 268, 269, 270, 271, 272, 273, 274, 275, 0, 277,
+ -1, -1, -1, 296, 297, 298, 299, -1, -1, -1,
+ -1, -1, -1, 0, -1, -1, -1, -1, 296, 297,
+ 298, 299, 261, -1, 263, 264, 265, 266, 267, 268,
+ 269, 270, 271, 272, 273, 274, 275, 261, 277, 263,
+ 264, 265, -1, -1, 268, 269, 270, 271, 272, 273,
+ 274, 275, 0, 277, -1, -1, -1, 296, 297, 298,
+ 299, -1, -1, -1, -1, -1, -1, 0, -1, -1,
+ -1, -1, 296, 297, 298, 299, -1, 261, -1, 263,
+ 264, 265, -1, 0, 268, 269, 270, 271, 272, 273,
+ 274, 275, 0, 277, -1, 261, 0, 263, 264, 265,
+ 0, -1, 268, 269, 270, 271, 272, 273, 274, 275,
+ -1, 277, 296, 297, 298, 299, 0, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 296, 297, 298, 299, 261, -1, 263, 264, 265, 0,
+ -1, 268, 269, 270, 271, 272, 273, 274, 275, -1,
+ 277, 261, -1, 263, 264, 265, 0, -1, 268, 269,
+ 270, 271, 272, 273, 274, 275, -1, 277, -1, 296,
+ 297, 298, 299, -1, -1, -1, -1, -1, 0, -1,
+ -1, -1, -1, -1, -1, -1, 296, 297, 298, 299,
+ -1, -1, -1, -1, -1, 0, -1, -1, -1, -1,
+ -1, -1, -1, -1, 0, 261, -1, 263, 264, 265,
+ -1, -1, 268, 269, 270, 271, 272, 273, 274, 275,
+ 261, 277, 263, 264, 265, 0, -1, 268, 269, 270,
+ 271, 272, 273, 274, 275, -1, 0, -1, -1, -1,
+ 296, 297, 298, 299, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, 296, 297, 298, 299, 261,
+ -1, 263, 264, -1, -1, -1, 268, 269, 270, 271,
+ 272, 273, 274, 275, 261, 277, 263, 264, -1, -1,
+ -1, 268, 269, 270, 271, 272, 273, 274, 275, -1,
+ -1, -1, -1, -1, 296, 297, 298, 299, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, 298, 299, 261, -1, 263, 264, -1, -1, -1,
+ 268, 269, 270, 271, 272, 273, 274, 275, 261, -1,
+ 263, 264, -1, -1, -1, 268, 269, 270, 271, 272,
+ 273, 274, 275, -1, 261, -1, 263, 264, -1, -1,
+ 298, 299, -1, 261, -1, 263, 264, 261, -1, 263,
+ 264, 261, -1, 263, 264, 298, 299, -1, 268, 269,
+ 270, 271, 272, 273, -1, -1, -1, 261, -1, 263,
+ 264, 298, 299, -1, 268, 269, 270, 271, 272, 273,
+ 298, 299, -1, -1, 298, -1, -1, -1, 298, 299,
+ 261, -1, 263, 264, -1, -1, -1, 268, 269, 270,
+ 271, 272, 273, -1, 298, 299, -1, 261, -1, 263,
+ 264, -1, -1, -1, 268, 269, 270, 271, 272, 273,
+ -1, -1, -1, -1, -1, -1, -1, 298, 299, 261,
+ -1, 263, 264, -1, -1, -1, 268, 269, 270, 271,
+ 272, 273, -1, -1, 298, 299, 261, -1, 263, 264,
+ -1, -1, -1, 268, 269, 261, -1, 263, 264, -1,
+ -1, -1, 268, 269, -1, -1, 298, 299, -1, -1,
+ -1, -1, -1, -1, -1, -1, 261, -1, 263, 264,
+ -1, -1, -1, 298, 299, -1, -1, 261, -1, 263,
+ 264, -1, 298, 299, 268, 269, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 298, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 298, 299,
+ };
+ } /* End of class YyCheckClass */
+
+
+//t protected static final class YyRuleClass {
+
+//t public static final String yyRule [] = {
+//t "$accept : expr",
+//t "expr : or_expr",
+//t "location_path : relative_location_path",
+//t "location_path : absolute_location_path",
+//t "absolute_location_path : SLASH",
+//t "absolute_location_path : SLASH relative_location_path",
+//t "absolute_location_path : DOUBLE_SLASH relative_location_path",
+//t "relative_location_path : step",
+//t "relative_location_path : relative_location_path SLASH step",
+//t "relative_location_path : relative_location_path DOUBLE_SLASH step",
+//t "step : step_node_test",
+//t "step : AT step_node_test",
+//t "step : axis_name DOUBLE_COLON step_node_test",
+//t "step : DOT",
+//t "step : DOUBLE_DOT",
+//t "step_node_test : node_test",
+//t "step_node_test : step_node_test predicate",
+//t "axis_name : ANCESTOR",
+//t "axis_name : ANCESTOR_OR_SELF",
+//t "axis_name : ATTRIBUTE",
+//t "axis_name : CHILD",
+//t "axis_name : DESCENDANT",
+//t "axis_name : DESCENDANT_OR_SELF",
+//t "axis_name : FOLLOWING",
+//t "axis_name : FOLLOWING_SIBLING",
+//t "axis_name : NAMESPACE",
+//t "axis_name : PARENT",
+//t "axis_name : PRECEDING",
+//t "axis_name : PRECEDING_SIBLING",
+//t "axis_name : SELF",
+//t "node_test : name_test",
+//t "node_test : PROCESSING_INSTRUCTION LITERAL RP",
+//t "node_test : node_type RP",
+//t "predicate : LB expr RB",
+//t "primary_expr : variable_reference",
+//t "primary_expr : LP expr RP",
+//t "primary_expr : LITERAL",
+//t "primary_expr : number",
+//t "primary_expr : function_call",
+//t "function_call : function_name LP RP",
+//t "function_call : function_name LP argument_list RP",
+//t "argument_list : expr",
+//t "argument_list : expr COMMA argument_list",
+//t "union_expr : path_expr",
+//t "union_expr : union_expr PIPE path_expr",
+//t "path_expr : location_path",
+//t "path_expr : filter_expr",
+//t "path_expr : filter_expr SLASH relative_location_path",
+//t "path_expr : filter_expr DOUBLE_SLASH relative_location_path",
+//t "filter_expr : primary_expr",
+//t "filter_expr : filter_expr predicate",
+//t "or_expr : and_expr",
+//t "or_expr : or_expr OR and_expr",
+//t "and_expr : equality_expr",
+//t "and_expr : and_expr AND equality_expr",
+//t "equality_expr : relational_expr",
+//t "equality_expr : equality_expr EQ relational_expr",
+//t "equality_expr : equality_expr NE relational_expr",
+//t "relational_expr : additive_expr",
+//t "relational_expr : relational_expr LT additive_expr",
+//t "relational_expr : relational_expr GT additive_expr",
+//t "relational_expr : relational_expr LTE additive_expr",
+//t "relational_expr : relational_expr GTE additive_expr",
+//t "additive_expr : multiplicative_expr",
+//t "additive_expr : additive_expr PLUS multiplicative_expr",
+//t "additive_expr : additive_expr MINUS multiplicative_expr",
+//t "multiplicative_expr : unary_expr",
+//t "multiplicative_expr : multiplicative_expr STAR unary_expr",
+//t "multiplicative_expr : multiplicative_expr DIV unary_expr",
+//t "multiplicative_expr : multiplicative_expr MOD unary_expr",
+//t "unary_expr : union_expr",
+//t "unary_expr : MINUS unary_expr",
+//t "number : DIGITS",
+//t "number : DIGITS DOT",
+//t "number : DIGITS DOT DIGITS",
+//t "number : DOT DIGITS",
+//t "function_name : qname",
+//t "variable_reference : DOLLAR qname",
+//t "name_test : STAR",
+//t "name_test : NAME COLON STAR",
+//t "name_test : qname",
+//t "qname : NAME",
+//t "qname : NAME COLON NAME",
+//t "node_type : COMMENT",
+//t "node_type : TEXT",
+//t "node_type : PROCESSING_INSTRUCTION",
+//t "node_type : NODE",
+//t };
+//t } /* End of class YyRuleClass */
+
+ protected static final class YyNameClass {
+
+ public static final String yyName [] = {
+ "end-of-file",null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,null,null,null,null,null,null,null,
+ null,null,null,null,null,null,null,"LITERAL","DIGITS","NAME","LP",
+ "RP","LB","RB","COMMA","PIPE","SLASH","DOUBLE_SLASH","EQ","NE","GT",
+ "LT","GTE","LTE","PLUS","MINUS","AT","STAR","DOLLAR","COLON",
+ "DOUBLE_COLON","DOT","DOUBLE_DOT","ANCESTOR","ANCESTOR_OR_SELF",
+ "ATTRIBUTE","CHILD","DESCENDANT","DESCENDANT_OR_SELF","FOLLOWING",
+ "FOLLOWING_SIBLING","NAMESPACE","PARENT","PRECEDING",
+ "PRECEDING_SIBLING","SELF","DIV","MOD","OR","AND","COMMENT",
+ "PROCESSING_INSTRUCTION","TEXT","NODE","UNARY",
+ };
+ } /* End of class YyNameClass */
+
+
+ // line 783 "XPathParser.y"
+
+}
+ // line 1463 "-"
diff --git a/libjava/classpath/gnu/xml/xpath/XPathParser.y b/libjava/classpath/gnu/xml/xpath/XPathParser.y
new file mode 100644
index 000000000..a6d3fd130
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/XPathParser.y
@@ -0,0 +1,794 @@
+%{
+/* XPathParser.y - An XPath 1.0 parser.
+ Copyright (C) 2004 The 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.xml.xpath;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import javax.xml.namespace.NamespaceContext;
+import javax.xml.namespace.QName;
+import javax.xml.xpath.XPathFunctionResolver;
+import javax.xml.xpath.XPathVariableResolver;
+import org.w3c.dom.Node;
+
+/**
+ * An XPath 1.0 parser.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class XPathParser
+{
+
+ NamespaceContext namespaceContext;
+ XPathVariableResolver variableResolver;
+ XPathFunctionResolver functionResolver;
+
+ QName getQName(String name)
+ {
+ QName qName = QName.valueOf(name);
+ if (namespaceContext != null)
+ {
+ String prefix = qName.getPrefix();
+ String uri = qName.getNamespaceURI();
+ if (prefix != null && (uri == null || uri.length() == 0))
+ {
+ uri = namespaceContext.getNamespaceURI(prefix);
+ String localName = qName.getLocalPart();
+ qName = new QName(uri, localName, prefix);
+ }
+ }
+ return qName;
+ }
+
+ Expr lookupFunction(String name, List<Expr> args)
+ {
+ int arity = args.size();
+ if ("position".equals(name) && arity == 0)
+ {
+ return new PositionFunction();
+ }
+ else if ("last".equals(name) && arity == 0)
+ {
+ return new LastFunction();
+ }
+ else if ("string".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new StringFunction(args);
+ }
+ else if ("number".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NumberFunction(args);
+ }
+ else if ("boolean".equals(name) && arity == 1)
+ {
+ return new BooleanFunction(args);
+ }
+ else if ("count".equals(name) && arity == 1)
+ {
+ return new CountFunction(args);
+ }
+ else if ("not".equals(name) && arity == 1)
+ {
+ return new NotFunction(args);
+ }
+ else if ("id".equals(name) && arity == 1)
+ {
+ return new IdFunction(args);
+ }
+ else if ("concat".equals(name) && arity > 1)
+ {
+ return new ConcatFunction(args);
+ }
+ else if ("true".equals(name) && arity == 0)
+ {
+ return new TrueFunction();
+ }
+ else if ("false".equals(name) && arity == 0)
+ {
+ return new FalseFunction();
+ }
+ else if ("name".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NameFunction(args);
+ }
+ else if ("local-name".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new LocalNameFunction(args);
+ }
+ else if ("namespace-uri".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NamespaceUriFunction(args);
+ }
+ else if ("starts-with".equals(name) && arity == 2)
+ {
+ return new StartsWithFunction(args);
+ }
+ else if ("contains".equals(name) && arity == 2)
+ {
+ return new ContainsFunction(args);
+ }
+ else if ("string-length".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new StringLengthFunction(args);
+ }
+ else if ("translate".equals(name) && arity == 3)
+ {
+ return new TranslateFunction(args);
+ }
+ else if ("normalize-space".equals(name) && (arity == 1 || arity == 0))
+ {
+ return new NormalizeSpaceFunction(args);
+ }
+ else if ("substring".equals(name) && (arity == 2 || arity == 3))
+ {
+ return new SubstringFunction(args);
+ }
+ else if ("substring-before".equals(name) && arity == 2)
+ {
+ return new SubstringBeforeFunction(args);
+ }
+ else if ("substring-after".equals(name) && arity == 2)
+ {
+ return new SubstringAfterFunction(args);
+ }
+ else if ("lang".equals(name) && arity == 1)
+ {
+ return new LangFunction(args);
+ }
+ else if ("sum".equals(name) && arity == 1)
+ {
+ return new SumFunction(args);
+ }
+ else if ("floor".equals(name) && arity == 1)
+ {
+ return new FloorFunction(args);
+ }
+ else if ("ceiling".equals(name) && arity == 1)
+ {
+ return new CeilingFunction(args);
+ }
+ else if ("round".equals(name) && arity == 1)
+ {
+ return new RoundFunction(args);
+ }
+ else if (functionResolver != null)
+ {
+ QName qName = QName.valueOf(name);
+ Object function = functionResolver.resolveFunction(qName, arity);
+ if (function != null &&
+ function instanceof Function &&
+ function instanceof Expr)
+ {
+ Function f = (Function) function;
+ f.setArguments(args);
+ return (Expr) function;
+ }
+ }
+ return new FunctionCall(functionResolver, name, args);
+ }
+
+%}
+
+%token LITERAL
+%token DIGITS
+%token NAME
+
+%token LP // '('
+%token RP // ')'
+%token LB // '['
+%token RB // ']'
+%token COMMA // ','
+%token PIPE // '|'
+%token SLASH // '/'
+%token DOUBLE_SLASH // '//'
+%token EQ // '='
+%token NE // '!='
+%token GT // '>'
+%token LT // '<'
+%token GTE // '>='
+%token LTE // '<='
+%token PLUS // '+'
+%token MINUS // '-'
+%token AT // '@'
+%token STAR // '*'
+%token DOLLAR // '$'
+%token COLON // ':'
+%token DOUBLE_COLON // '::'
+%token DOT // '.'
+%token DOUBLE_DOT // '..'
+
+%token ANCESTOR
+%token ANCESTOR_OR_SELF
+%token ATTRIBUTE
+%token CHILD
+%token DESCENDANT
+%token DESCENDANT_OR_SELF
+%token FOLLOWING
+%token FOLLOWING_SIBLING
+%token NAMESPACE
+%token PARENT
+%token PRECEDING
+%token PRECEDING_SIBLING
+%token SELF
+%token DIV
+%token MOD
+%token OR
+%token AND
+%token COMMENT
+%token PROCESSING_INSTRUCTION
+%token TEXT
+%token NODE
+
+%right UNARY
+
+%start expr
+
+%%
+
+expr:
+ or_expr
+ ;
+
+location_path:
+ relative_location_path
+ | absolute_location_path
+ ;
+
+absolute_location_path:
+ SLASH
+ {
+ $$ = new Root();
+ }
+ | SLASH relative_location_path
+ {
+ Steps steps;
+ if ($2 instanceof Steps)
+ {
+ steps = (Steps) $2;
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst((Expr) $2);
+ }
+ steps.path.addFirst(new Root());
+ $$ = steps;
+ //$$ = new Step(new Root(), (Path) $2);
+ }
+ | DOUBLE_SLASH relative_location_path
+ {
+ Test nt = new NodeTypeTest((short) 0);
+ Selector s = new Selector(Selector.DESCENDANT_OR_SELF,
+ Collections.singletonList (nt));
+ Steps steps;
+ if ($2 instanceof Steps)
+ {
+ steps = (Steps) $2;
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst((Expr) $2);
+ }
+ steps.path.addFirst(s);
+ steps.path.addFirst(new Root());
+ $$ = steps;
+ //Step step = new Step(s, (Path) $2);
+ //$$ = new Step(new Root(), step);
+ }
+ ;
+
+relative_location_path:
+ step
+ | relative_location_path SLASH step
+ {
+ Steps steps;
+ if ($1 instanceof Steps)
+ {
+ steps = (Steps) $1;
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst((Expr) $1);
+ }
+ steps.path.addLast((Expr) $3);
+ $$ = steps;
+ //$$ = new Step((Expr) $1, (Path) $3);
+ }
+ | relative_location_path DOUBLE_SLASH step
+ {
+ Test nt = new NodeTypeTest((short) 0);
+ Selector s = new Selector(Selector.DESCENDANT_OR_SELF,
+ Collections.singletonList (nt));
+ Steps steps;
+ if ($1 instanceof Steps)
+ {
+ steps = (Steps) $1;
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst((Expr) $1);
+ }
+ steps.path.addLast(s);
+ steps.path.addLast((Expr) $3);
+ $$ = steps;
+ //Step step = new Step(s, (Path) $3);
+ //$$ = new Step((Expr) $1, step);
+ }
+ ;
+
+step:
+ step_node_test
+ {
+ @SuppressWarnings("unchecked") List<Test> tests = (List<Test>) $1;
+ $$ = new Selector (Selector.CHILD, tests);
+ }
+ | AT step_node_test
+ {
+ @SuppressWarnings("unchecked") List<Test> tests = (List<Test>) $2;
+ $$ = new Selector (Selector.ATTRIBUTE, tests);
+ }
+ | axis_name DOUBLE_COLON step_node_test
+ {
+ @SuppressWarnings("unchecked") List<Test> tests = (List<Test>) $3;
+ $$ = new Selector (((Integer) $1).intValue (), tests);
+ }
+ | DOT
+ {
+ List<Test> emptyList = Collections.emptyList();
+ $$ = new Selector (Selector.SELF, emptyList);
+ }
+ | DOUBLE_DOT
+ {
+ List<Test> emptyList = Collections.emptyList();
+ $$ = new Selector (Selector.PARENT, emptyList);
+ }
+ ;
+
+step_node_test:
+ node_test
+ {
+ List<Test> list = new ArrayList<Test>();
+ list.add((Test) $1);
+ $$ = list;
+ }
+ | step_node_test predicate
+ {
+ /* This is safe as we create this in one of the other cases */
+ @SuppressWarnings("unchecked") List<Test> tests = (List<Test>)$1;
+ tests.add((Test) $2);
+ $$ = list;
+ }
+ ;
+
+/*predicate_list:
+ predicate
+ {
+ List list = new ArrayList ();
+ list.add ($1);
+ $$ = list;
+ }
+ | predicate predicate_list
+ {
+ List list = (List) $3;
+ list.add (0, $1);
+ $$ = list;
+ }
+ ;*/
+
+axis_name:
+ ANCESTOR
+ {
+ $$ = new Integer(Selector.ANCESTOR);
+ }
+ | ANCESTOR_OR_SELF
+ {
+ $$ = new Integer(Selector.ANCESTOR_OR_SELF);
+ }
+ | ATTRIBUTE
+ {
+ $$ = new Integer(Selector.ATTRIBUTE);
+ }
+ | CHILD
+ {
+ $$ = new Integer(Selector.CHILD);
+ }
+ | DESCENDANT
+ {
+ $$ = new Integer(Selector.DESCENDANT);
+ }
+ | DESCENDANT_OR_SELF
+ {
+ $$ = new Integer(Selector.DESCENDANT_OR_SELF);
+ }
+ | FOLLOWING
+ {
+ $$ = new Integer(Selector.FOLLOWING);
+ }
+ | FOLLOWING_SIBLING
+ {
+ $$ = new Integer(Selector.FOLLOWING_SIBLING);
+ }
+ | NAMESPACE
+ {
+ $$ = new Integer(Selector.NAMESPACE);
+ }
+ | PARENT
+ {
+ $$ = new Integer(Selector.PARENT);
+ }
+ | PRECEDING
+ {
+ $$ = new Integer(Selector.PRECEDING);
+ }
+ | PRECEDING_SIBLING
+ {
+ $$ = new Integer(Selector.PRECEDING_SIBLING);
+ }
+ | SELF
+ {
+ $$ = new Integer(Selector.SELF);
+ }
+ ;
+
+node_test:
+ name_test
+ /*| PROCESSING_INSTRUCTION LP LITERAL RP*/
+ | PROCESSING_INSTRUCTION LITERAL RP
+ {
+ $$ = new NodeTypeTest(Node.PROCESSING_INSTRUCTION_NODE, (String) $2);
+ }
+ /*| node_type LP RP*/
+ | node_type RP
+ {
+ $$ = new NodeTypeTest(((Short) $1).shortValue());
+ }
+ ;
+
+predicate:
+ LB expr RB
+ {
+ $$ = new Predicate((Expr) $2);
+ }
+ ;
+
+primary_expr:
+ variable_reference
+ | LP expr RP
+ {
+ $$ = new ParenthesizedExpr((Expr) $2);
+ }
+ | LITERAL
+ {
+ $$ = new Constant($1);
+ }
+ | number
+ {
+ $$ = new Constant($1);
+ }
+ | function_call
+ ;
+
+function_call:
+ function_name LP RP
+ {
+ List<Expr> emptyList = Collections.emptyList();
+ $$ = lookupFunction((String) $1, emptyList);
+ }
+ | function_name LP argument_list RP
+ {
+ /* This is safe as we create this below */
+ @SuppressWarnings("unchecked") List<Expr> exprs = (List<Expr>) $3;
+ $$ = lookupFunction((String) $1, (List) exprs);
+ }
+ ;
+
+argument_list:
+ expr
+ {
+ List<Expr> list = new ArrayList<Expr>();
+ list.add((Expr) $1);
+ $$ = list;
+ }
+ | expr COMMA argument_list
+ {
+ /* This is safe as we create this above */
+ @SuppressWarnings("unchecked") List<Expr> list = (List<Expr>) $3;
+ list.add(0, (Expr) $1);
+ $$ = list;
+ }
+ ;
+
+union_expr:
+ path_expr
+ | union_expr PIPE path_expr
+ {
+ $$ = new UnionExpr((Expr) $1, (Expr) $3);
+ }
+ ;
+
+path_expr:
+ location_path
+ | filter_expr
+ | filter_expr SLASH relative_location_path
+ {
+ Steps steps;
+ if ($3 instanceof Steps)
+ {
+ steps = (Steps) $3;
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst((Expr) $3);
+ }
+ steps.path.addFirst((Expr) $1);
+ $$ = steps;
+ //$$ = new Step ((Expr) $1, (Path) $3);
+ }
+ | filter_expr DOUBLE_SLASH relative_location_path
+ {
+ Test nt = new NodeTypeTest((short) 0);
+ Selector s = new Selector(Selector.DESCENDANT_OR_SELF,
+ Collections.singletonList(nt));
+ Steps steps;
+ if ($3 instanceof Steps)
+ {
+ steps = (Steps) $3;
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst($3);
+ }
+ steps.path.addFirst(s);
+ steps.path.addFirst((Expr) $1);
+ $$ = steps;
+ //Step step = new Step (s, (Path) $3);
+ //$$ = new Step ((Expr) $1, step);
+ }
+ ;
+
+filter_expr:
+ primary_expr
+ | filter_expr predicate
+ {
+ Predicate filter = (Predicate) $2;
+ Selector s = new Selector(Selector.SELF,
+ Collections.singletonList(filter));
+ Steps steps;
+ if ($1 instanceof Steps)
+ {
+ steps = (Steps) $1;
+ }
+ else
+ {
+ steps = new Steps();
+ steps.path.addFirst((Expr) $1);
+ }
+ steps.path.addLast(s);
+ $$ = steps;
+ //$$ = new Step ((Expr) $1, s);
+ }
+ ;
+
+or_expr:
+ and_expr
+ | or_expr OR and_expr
+ {
+ $$ = new OrExpr((Expr) $1, (Expr) $3);
+ }
+ ;
+
+and_expr:
+ equality_expr
+ | and_expr AND equality_expr
+ {
+ $$ = new AndExpr((Expr) $1, (Expr) $3);
+ }
+ ;
+
+equality_expr:
+ relational_expr
+ | equality_expr EQ relational_expr
+ {
+ $$ = new EqualityExpr((Expr) $1, (Expr) $3, false);
+ }
+ | equality_expr NE relational_expr
+ {
+ $$ = new EqualityExpr((Expr) $1, (Expr) $3, true);
+ }
+ ;
+
+relational_expr:
+ additive_expr
+ | relational_expr LT additive_expr
+ {
+ $$ = new RelationalExpr((Expr) $1, (Expr) $3, true, false);
+ }
+ | relational_expr GT additive_expr
+ {
+ $$ = new RelationalExpr((Expr) $1, (Expr) $3, false, false);
+ }
+ | relational_expr LTE additive_expr
+ {
+ $$ = new RelationalExpr((Expr) $1, (Expr) $3, true, true);
+ }
+ | relational_expr GTE additive_expr
+ {
+ $$ = new RelationalExpr((Expr) $1, (Expr) $3, false, true);
+ }
+ ;
+
+additive_expr:
+ multiplicative_expr
+ | additive_expr PLUS multiplicative_expr
+ {
+ $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.ADD);
+ }
+ | additive_expr MINUS multiplicative_expr
+ {
+ $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.SUBTRACT);
+ }
+ ;
+
+multiplicative_expr:
+ unary_expr
+ | multiplicative_expr STAR unary_expr
+ {
+ $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.MULTIPLY);
+ }
+ | multiplicative_expr DIV unary_expr
+ {
+ $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.DIVIDE);
+ }
+ | multiplicative_expr MOD unary_expr
+ {
+ $$ = new ArithmeticExpr((Expr) $1, (Expr) $3, ArithmeticExpr.MODULO);
+ }
+ ;
+
+unary_expr:
+ union_expr
+ | MINUS unary_expr %prec UNARY
+ {
+ $$ = new NegativeExpr((Expr) $2);
+ }
+ ;
+
+number:
+ DIGITS
+ {
+ $$ = new Double((String) $1 + ".0");
+ }
+ | DIGITS DOT
+ {
+ $$ = new Double((String) $1 + ".0");
+ }
+ | DIGITS DOT DIGITS
+ {
+ $$ = new Double((String) $1 + "." + (String) $3);
+ }
+ | DOT DIGITS
+ {
+ $$ = new Double("0." + (String) $2);
+ }
+ ;
+
+function_name:
+ qname
+/* | node_type
+ {
+ switch (((Short) $1).shortValue ())
+ {
+ case Node.COMMENT_NODE:
+ $$ = "comment";
+ break;
+ case Node.TEXT_NODE:
+ $$ = "text";
+ break;
+ case Node.PROCESSING_INSTRUCTION_NODE:
+ $$ = "processing-instruction";
+ break;
+ default:
+ $$ = "node";
+ break;
+ }
+ }*/
+ ;
+
+variable_reference:
+ DOLLAR qname
+ {
+ String name = (String) $2;
+ $$ = new VariableReference(variableResolver, getQName(name));
+ }
+ ;
+
+name_test:
+ STAR
+ {
+ $$ = new NameTest(null, true, true);
+ }
+ | NAME COLON STAR
+ {
+ QName qName = getQName((String) $1);
+ $$ = new NameTest(qName, true, false);
+ }
+ | qname
+ {
+ QName qName = getQName((String) $1);
+ $$ = new NameTest(qName, false, false);
+ }
+ ;
+
+qname:
+ NAME
+ | NAME COLON NAME
+ {
+ $$ = (String) $1 + ':' + (String) $3;
+ }
+ ;
+
+node_type:
+ COMMENT
+ {
+ $$ = new Short(Node.COMMENT_NODE);
+ }
+ | TEXT
+ {
+ $$ = new Short(Node.TEXT_NODE);
+ }
+ | PROCESSING_INSTRUCTION
+ {
+ $$ = new Short(Node.PROCESSING_INSTRUCTION_NODE);
+ }
+ | NODE
+ {
+ $$ = new Short((short) 0);
+ }
+ ;
+
+%%
+
+}
diff --git a/libjava/classpath/gnu/xml/xpath/XPathTokenizer.java b/libjava/classpath/gnu/xml/xpath/XPathTokenizer.java
new file mode 100644
index 000000000..879931bd5
--- /dev/null
+++ b/libjava/classpath/gnu/xml/xpath/XPathTokenizer.java
@@ -0,0 +1,594 @@
+/* XPathTokenizer.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.xpath;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.Map;
+import java.util.TreeMap;
+
+/*import antlr.Token;
+import antlr.TokenStream;
+import antlr.TokenStreamException;
+import antlr.TokenStreamIOException;*/
+
+/**
+ * XPath 1.0 expression tokenizer.
+ *
+ * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a>
+ */
+public class XPathTokenizer
+implements XPathParser.yyInput
+//implements TokenStream
+{
+
+ static class XPathToken
+ //extends Token
+ {
+
+ int type;
+ String val;
+
+ XPathToken (int type)
+ {
+ this (type, null);
+ }
+
+ XPathToken (int type, String val)
+ {
+ //super (type);
+ this.type = type;
+ this.val = val;
+ }
+
+ public String getText ()
+ {
+ return val;
+ }
+
+ public String toString ()
+ {
+ return val;
+ }
+
+ }
+
+ static final Map<String,Integer> keywords = new TreeMap<String,Integer> ();
+ static
+ {
+ keywords.put ("ancestor", new Integer (XPathParser.ANCESTOR));
+ keywords.put ("ancestor-or-self", new Integer (XPathParser.ANCESTOR_OR_SELF));
+ keywords.put ("attribute", new Integer (XPathParser.ATTRIBUTE));
+ keywords.put ("child", new Integer (XPathParser.CHILD));
+ keywords.put ("descendant", new Integer (XPathParser.DESCENDANT));
+ keywords.put ("descendant-or-self", new Integer (XPathParser.DESCENDANT_OR_SELF));
+ keywords.put ("following", new Integer (XPathParser.FOLLOWING));
+ keywords.put ("following-sibling", new Integer (XPathParser.FOLLOWING_SIBLING));
+ keywords.put ("namespace", new Integer (XPathParser.NAMESPACE));
+ keywords.put ("parent", new Integer (XPathParser.PARENT));
+ keywords.put ("preceding", new Integer (XPathParser.PRECEDING));
+ keywords.put ("preceding-sibling", new Integer (XPathParser.PRECEDING_SIBLING));
+ keywords.put ("self", new Integer (XPathParser.SELF));
+ keywords.put ("div", new Integer (XPathParser.DIV));
+ keywords.put ("mod", new Integer (XPathParser.MOD));
+ keywords.put ("or", new Integer (XPathParser.OR));
+ keywords.put ("and", new Integer (XPathParser.AND));
+ keywords.put ("comment", new Integer (XPathParser.COMMENT));
+ keywords.put ("processing-instruction", new Integer (XPathParser.PROCESSING_INSTRUCTION));
+ keywords.put ("text", new Integer (XPathParser.TEXT));
+ keywords.put ("node", new Integer (XPathParser.NODE));
+ }
+
+ Reader in;
+ XPathToken token;
+ XPathToken lastToken;
+
+ public XPathTokenizer (String expr)
+ {
+ this (new StringReader (expr));
+ }
+
+ XPathTokenizer (Reader in)
+ {
+ this.in = in.markSupported () ? in : new BufferedReader (in);
+ }
+
+ /* Begin ANTLR specific *
+
+ public Token nextToken ()
+ throws TokenStreamException
+ {
+ try
+ {
+ if (!advance ())
+ {
+ throw new TokenStreamException ("eof");
+ }
+ token ();
+ return token;
+ }
+ catch (IOException e)
+ {
+ throw new TokenStreamIOException (e);
+ }
+ }
+
+ * End ANTLR specific */
+
+ public boolean advance ()
+ throws IOException
+ {
+ lastToken = token;
+ int c = in.read ();
+ switch (c)
+ {
+ case -1: // eof
+ return false;
+ case 0x20:
+ case 0x09:
+ case 0x0d:
+ case 0x0a: // skip whitespace
+ return advance ();
+ case 0x22: // "
+ case 0x27: // '
+ token = consume_literal (c);
+ break;
+ case 0x28: // (
+ token = new XPathToken (XPathParser.LP);
+ break;
+ case 0x29: // )
+ token = new XPathToken (XPathParser.RP);
+ break;
+ case 0x5b: // [
+ token = new XPathToken (XPathParser.LB);
+ break;
+ case 0x5d: // ]
+ token = new XPathToken (XPathParser.RB);
+ break;
+ case 0x2c: // ,
+ token = new XPathToken (XPathParser.COMMA);
+ break;
+ case 0x7c: // |
+ token = new XPathToken (XPathParser.PIPE);
+ break;
+ case 0x2f: // /
+ in.mark (1);
+ int d1 = in.read ();
+ if (d1 == 0x2f)
+ {
+ token = new XPathToken (XPathParser.DOUBLE_SLASH);
+ }
+ else
+ {
+ in.reset ();
+ token = new XPathToken (XPathParser.SLASH);
+ }
+ break;
+ case 0x3d: // =
+ token = new XPathToken (XPathParser.EQ);
+ break;
+ case 0x21: // !
+ in.mark (1);
+ int d2 = in.read ();
+ if (d2 == 0x3d) // =
+ {
+ token = new XPathToken (XPathParser.NE);
+ }
+ else
+ {
+ in.reset ();
+ token = new XPathToken (XPathParser.yyErrorCode);
+ }
+ break;
+ case 0x3e: // >
+ in.mark (1);
+ int d3 = in.read ();
+ if (d3 == 0x3d) // =
+ {
+ token = new XPathToken (XPathParser.GTE);
+ }
+ else
+ {
+ in.reset ();
+ token = new XPathToken (XPathParser.GT);
+ }
+ break;
+ case 0x3c: // <
+ in.mark (1);
+ int d4 = in.read ();
+ if (d4 == 0x3d) // =
+ {
+ token = new XPathToken (XPathParser.LTE);
+ }
+ else
+ {
+ in.reset ();
+ token = new XPathToken (XPathParser.LT);
+ }
+ break;
+ case 0x2b: // +
+ token = new XPathToken (XPathParser.PLUS);
+ break;
+ case 0x2d: // -
+ token = new XPathToken (XPathParser.MINUS);
+ break;
+ case 0x40: // @
+ token = new XPathToken (XPathParser.AT);
+ break;
+ case 0x2a: // *
+ token = new XPathToken (XPathParser.STAR);
+ break;
+ case 0x24: // $
+ token = new XPathToken (XPathParser.DOLLAR);
+ break;
+ case 0x3a: // :
+ in.mark (1);
+ int d5 = in.read ();
+ if (d5 == 0x3a)
+ {
+ token = new XPathToken (XPathParser.DOUBLE_COLON);
+ }
+ else
+ {
+ in.reset ();
+ token = new XPathToken (XPathParser.COLON);
+ }
+ break;
+ case 0x2e: // .
+ in.mark (1);
+ int d6 = in.read ();
+ if (d6 == 0x2e)
+ {
+ token = new XPathToken (XPathParser.DOUBLE_DOT);
+ }
+ else
+ {
+ in.reset ();
+ token = new XPathToken (XPathParser.DOT);
+ }
+ break;
+ default:
+ if (c >= 0x30 && c <= 0x39)
+ {
+ token = consume_digits (c);
+ }
+ else if (c == 0x5f || Character.isLetter ((char) c))
+ {
+ token = consume_name (c);
+ }
+ else
+ {
+ token = new XPathToken (XPathParser.yyErrorCode);
+ }
+ }
+ return true;
+ }
+
+ public int token ()
+ {
+ return token.type;
+ }
+
+ public Object value ()
+ {
+ return token.val;
+ }
+
+ XPathToken consume_literal (int delimiter)
+ throws IOException
+ {
+ CPStringBuilder buf = new CPStringBuilder ();
+ while (true)
+ {
+ int c = in.read ();
+ if (c == -1)
+ {
+ return new XPathToken (XPathParser.yyErrorCode);
+ }
+ else if (c == delimiter)
+ {
+ return new XPathToken (XPathParser.LITERAL, buf.toString ());
+ }
+ else
+ {
+ buf.append ((char) c);
+ }
+ }
+ }
+
+ XPathToken consume_digits (int c)
+ throws IOException
+ {
+ CPStringBuilder buf = new CPStringBuilder ();
+ buf.append ((char) c);
+ while (true)
+ {
+ in.mark (1);
+ c = in.read ();
+ if (c >= 0x30 && c <= 0x39)
+ {
+ buf.append ((char) c);
+ }
+ else
+ {
+ in.reset ();
+ return new XPathToken (XPathParser.DIGITS, buf.toString ());
+ }
+ }
+ }
+
+ XPathToken consume_name (int c)
+ throws IOException
+ {
+ CPStringBuilder buf = new CPStringBuilder ();
+ buf.append ((char) c);
+ while (true)
+ {
+ in.mark (1);
+ c = in.read ();
+ if (isNameChar (c))
+ {
+ buf.append ((char) c);
+ }
+ else
+ {
+ in.reset ();
+ String name = buf.toString ();
+ Integer keyword = (Integer) keywords.get (name);
+ if (keyword == null)
+ {
+ return new XPathToken (XPathParser.NAME, name);
+ }
+ else
+ {
+ int val = keyword.intValue ();
+ switch (val)
+ {
+ case XPathParser.NODE:
+ case XPathParser.COMMENT:
+ case XPathParser.TEXT:
+ case XPathParser.PROCESSING_INSTRUCTION:
+ // Consume subsequent (
+ in.mark (1);
+ do
+ {
+ c = in.read ();
+ }
+ while (c == 0x20 || c == 0x09);
+ if (c != 0x28)
+ {
+ in.reset ();
+ return new XPathToken (XPathParser.NAME, name);
+ }
+ break;
+ case XPathParser.CHILD:
+ case XPathParser.PARENT:
+ case XPathParser.SELF:
+ case XPathParser.DESCENDANT:
+ case XPathParser.ANCESTOR:
+ case XPathParser.DESCENDANT_OR_SELF:
+ case XPathParser.ANCESTOR_OR_SELF:
+ case XPathParser.ATTRIBUTE:
+ case XPathParser.NAMESPACE:
+ case XPathParser.FOLLOWING:
+ case XPathParser.FOLLOWING_SIBLING:
+ case XPathParser.PRECEDING:
+ case XPathParser.PRECEDING_SIBLING:
+ // Check that this is an axis specifier
+ in.mark(1);
+ do
+ {
+ c = in.read();
+ }
+ while (c == 0x20 || c == 0x09);
+ if (c == 0x3a)
+ {
+ c = in.read();
+ if (c == 0x3a)
+ {
+ in.reset();
+ return new XPathToken(val);
+ }
+ }
+ in.reset();
+ return new XPathToken(XPathParser.NAME, name);
+ case XPathParser.DIV:
+ case XPathParser.MOD:
+ // May be a name
+ if (lastToken == null)
+ {
+ return new XPathToken(XPathParser.NAME, name);
+ }
+ switch (lastToken.type)
+ {
+ case XPathParser.LP:
+ case XPathParser.LB:
+ case XPathParser.COMMA:
+ case XPathParser.PIPE:
+ case XPathParser.EQ:
+ case XPathParser.NE:
+ case XPathParser.GT:
+ case XPathParser.LT:
+ case XPathParser.GTE:
+ case XPathParser.LTE:
+ case XPathParser.PLUS:
+ case XPathParser.MINUS:
+ case XPathParser.STAR:
+ case XPathParser.AT:
+ case XPathParser.DOLLAR:
+ case XPathParser.COLON:
+ case XPathParser.DOUBLE_COLON:
+ case XPathParser.DIV:
+ case XPathParser.MOD:
+ case XPathParser.OR:
+ case XPathParser.AND:
+ case XPathParser.SLASH:
+ return new XPathToken(XPathParser.NAME, name);
+ }
+ break;
+ }
+ return new XPathToken (val);
+ }
+ }
+ }
+ }
+
+ boolean isNameChar (int c)
+ {
+ /* Name */
+ return (c == 0x5f
+ || c == 0x2d
+ || c == 0x2e
+ || (c >= 0x30 && c <= 0x39)
+ /* CombiningChar */
+ || (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
+ /* Extender */
+ || 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)
+ /* Name */
+ || Character.isLetter ((char) c));
+ }
+
+}