From 554fd8c5195424bdbcabf5de30fdc183aba391bd Mon Sep 17 00:00:00 2001 From: upstream source tree Date: Sun, 15 Mar 2015 20:14:05 -0400 Subject: obtained gcc-4.6.4.tar.bz2 from upstream website; verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository. --- libjava/classpath/gnu/java/awt/AWTUtilities.java | 898 +++++++ libjava/classpath/gnu/java/awt/BitMaskExtent.java | 79 + .../gnu/java/awt/BitwiseXORComposite.java | 295 +++ libjava/classpath/gnu/java/awt/Buffers.java | 225 ++ .../gnu/java/awt/ClasspathGraphicsEnvironment.java | 67 + .../classpath/gnu/java/awt/ClasspathToolkit.java | 231 ++ .../gnu/java/awt/ComponentDataBlitOp.java | 156 ++ .../gnu/java/awt/ComponentReshapeEvent.java | 85 + libjava/classpath/gnu/java/awt/EmbeddedWindow.java | 138 + libjava/classpath/gnu/java/awt/EventModifier.java | 107 + .../gnu/java/awt/GradientPaintContext.java | 164 ++ .../classpath/gnu/java/awt/LowPriorityEvent.java | 48 + .../gnu/java/awt/color/CieXyzConverter.java | 73 + .../gnu/java/awt/color/ClutProfileConverter.java | 152 ++ .../gnu/java/awt/color/ColorLookUpTable.java | 429 ++++ .../gnu/java/awt/color/ColorSpaceConverter.java | 69 + .../gnu/java/awt/color/GrayProfileConverter.java | 137 + .../gnu/java/awt/color/GrayScaleConverter.java | 110 + .../gnu/java/awt/color/LinearRGBConverter.java | 152 ++ .../gnu/java/awt/color/ProfileHeader.java | 398 +++ .../gnu/java/awt/color/PyccConverter.java | 71 + .../gnu/java/awt/color/RgbProfileConverter.java | 244 ++ .../gnu/java/awt/color/SrgbConverter.java | 152 ++ libjava/classpath/gnu/java/awt/color/TagEntry.java | 121 + .../gnu/java/awt/color/ToneReproductionCurve.java | 177 ++ libjava/classpath/gnu/java/awt/color/package.html | 46 + .../awt/dnd/GtkMouseDragGestureRecognizer.java | 172 ++ .../awt/dnd/peer/gtk/GtkDragSourceContextPeer.java | 184 ++ .../awt/dnd/peer/gtk/GtkDropTargetContextPeer.java | 125 + .../java/awt/dnd/peer/gtk/GtkDropTargetPeer.java | 68 + .../java/awt/doc-files/BitwiseXORComposite-1.png | Bin 0 -> 8845 bytes .../classpath/gnu/java/awt/font/FontDelegate.java | 329 +++ .../classpath/gnu/java/awt/font/FontFactory.java | 90 + .../gnu/java/awt/font/GNUGlyphVector.java | 663 +++++ .../gnu/java/awt/font/OpenTypeFontPeer.java | 565 +++++ .../gnu/java/awt/font/autofit/AutoHinter.java | 83 + .../gnu/java/awt/font/autofit/AxisHints.java | 112 + .../gnu/java/awt/font/autofit/Constants.java | 86 + .../classpath/gnu/java/awt/font/autofit/Edge.java | 82 + .../gnu/java/awt/font/autofit/GlyphHints.java | 640 +++++ .../gnu/java/awt/font/autofit/HintScaler.java | 53 + .../classpath/gnu/java/awt/font/autofit/Latin.java | 1363 ++++++++++ .../gnu/java/awt/font/autofit/LatinAxis.java | 62 + .../gnu/java/awt/font/autofit/LatinBlue.java | 61 + .../gnu/java/awt/font/autofit/LatinMetrics.java | 66 + .../gnu/java/awt/font/autofit/Script.java | 62 + .../gnu/java/awt/font/autofit/ScriptMetrics.java | 53 + .../gnu/java/awt/font/autofit/Segment.java | 97 + .../classpath/gnu/java/awt/font/autofit/Utils.java | 255 ++ .../classpath/gnu/java/awt/font/autofit/Width.java | 64 + .../gnu/java/awt/font/opentype/CharGlyphMap.java | 1027 ++++++++ .../gnu/java/awt/font/opentype/GlyphNamer.java | 1135 +++++++++ .../gnu/java/awt/font/opentype/Hinter.java | 63 + .../java/awt/font/opentype/MacResourceFork.java | 235 ++ .../gnu/java/awt/font/opentype/NameDecoder.java | 702 +++++ .../gnu/java/awt/font/opentype/OpenTypeFont.java | 882 +++++++ .../awt/font/opentype/OpenTypeFontFactory.java | 140 + .../gnu/java/awt/font/opentype/Scaler.java | 205 ++ .../gnu/java/awt/font/opentype/truetype/Fixed.java | 176 ++ .../awt/font/opentype/truetype/GlyphLoader.java | 447 ++++ .../awt/font/opentype/truetype/GlyphLocator.java | 187 ++ .../awt/font/opentype/truetype/GlyphMeasurer.java | 228 ++ .../gnu/java/awt/font/opentype/truetype/Point.java | 287 +++ .../awt/font/opentype/truetype/TrueTypeScaler.java | 380 +++ .../awt/font/opentype/truetype/VirtualMachine.java | 1815 +++++++++++++ .../gnu/java/awt/font/opentype/truetype/Zone.java | 291 +++ .../font/opentype/truetype/ZonePathIterator.java | 393 +++ .../truetype/doc-files/ZonePathIterator-1.dia | Bin 0 -> 1572 bytes .../truetype/doc-files/ZonePathIterator-1.png | Bin 0 -> 11278 bytes .../classpath/gnu/java/awt/image/AsyncImage.java | 300 +++ .../gnu/java/awt/image/ImageConverter.java | 528 ++++ .../classpath/gnu/java/awt/image/ImageDecoder.java | 188 ++ .../classpath/gnu/java/awt/image/XBMDecoder.java | 155 ++ libjava/classpath/gnu/java/awt/image/package.html | 46 + .../gnu/java/awt/java2d/AbstractGraphics2D.java | 2094 +++++++++++++++ .../classpath/gnu/java/awt/java2d/ActiveEdges.java | 197 ++ .../gnu/java/awt/java2d/AlphaCompositeContext.java | 316 +++ .../gnu/java/awt/java2d/CubicSegment.java | 184 ++ .../classpath/gnu/java/awt/java2d/ImagePaint.java | 192 ++ .../classpath/gnu/java/awt/java2d/LineSegment.java | 118 + .../gnu/java/awt/java2d/PixelCoverage.java | 132 + .../classpath/gnu/java/awt/java2d/Pixelizer.java | 56 + .../classpath/gnu/java/awt/java2d/PolyEdge.java | 171 ++ .../gnu/java/awt/java2d/PolyEdgeComparator.java | 70 + .../classpath/gnu/java/awt/java2d/QuadSegment.java | 260 ++ .../gnu/java/awt/java2d/RasterGraphics.java | 118 + .../classpath/gnu/java/awt/java2d/Scanline.java | 91 + .../gnu/java/awt/java2d/ScanlineConverter.java | 451 ++++ .../gnu/java/awt/java2d/ScanlineCoverage.java | 630 +++++ libjava/classpath/gnu/java/awt/java2d/Segment.java | 158 ++ .../classpath/gnu/java/awt/java2d/ShapeCache.java | 90 + .../gnu/java/awt/java2d/ShapeWrapper.java | 119 + .../gnu/java/awt/java2d/TextCacheKey.java | 153 ++ .../gnu/java/awt/java2d/TexturePaintContext.java | 211 ++ libjava/classpath/gnu/java/awt/package.html | 46 + .../gnu/java/awt/peer/ClasspathDesktopPeer.java | 301 +++ .../gnu/java/awt/peer/ClasspathFontPeer.java | 865 +++++++ .../gnu/java/awt/peer/EmbeddedWindowPeer.java | 47 + .../gnu/java/awt/peer/GLightweightPeer.java | 461 ++++ .../gnu/java/awt/peer/GnomeDesktopPeer.java | 155 ++ .../gnu/java/awt/peer/KDEDesktopPeer.java | 135 + .../java/awt/peer/NativeEventLoopRunningEvent.java | 58 + .../gnu/java/awt/peer/gtk/AsyncImage.java | 283 +++ .../java/awt/peer/gtk/BufferedImageGraphics.java | 538 ++++ .../gnu/java/awt/peer/gtk/CairoGraphics2D.java | 2176 ++++++++++++++++ .../gnu/java/awt/peer/gtk/CairoSurface.java | 428 ++++ .../java/awt/peer/gtk/CairoSurfaceGraphics.java | 355 +++ .../gnu/java/awt/peer/gtk/ComponentGraphics.java | 941 +++++++ .../java/awt/peer/gtk/ComponentGraphicsCopy.java | 122 + .../gnu/java/awt/peer/gtk/FreetypeGlyphVector.java | 630 +++++ .../gnu/java/awt/peer/gtk/GdkFontPeer.java | 545 ++++ .../awt/peer/gtk/GdkGraphicsConfiguration.java | 156 ++ .../java/awt/peer/gtk/GdkGraphicsEnvironment.java | 172 ++ .../gnu/java/awt/peer/gtk/GdkPixbufDecoder.java | 785 ++++++ .../gnu/java/awt/peer/gtk/GdkRobotPeer.java | 99 + .../java/awt/peer/gtk/GdkScreenGraphicsDevice.java | 362 +++ .../gnu/java/awt/peer/gtk/GtkButtonPeer.java | 93 + .../gnu/java/awt/peer/gtk/GtkCanvasPeer.java | 60 + .../java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java | 74 + .../gnu/java/awt/peer/gtk/GtkCheckboxPeer.java | 255 ++ .../gnu/java/awt/peer/gtk/GtkChoicePeer.java | 142 ++ .../gnu/java/awt/peer/gtk/GtkClipboard.java | 436 ++++ .../java/awt/peer/gtk/GtkClipboardNotifier.java | 129 + .../gnu/java/awt/peer/gtk/GtkComponentPeer.java | 920 +++++++ .../gnu/java/awt/peer/gtk/GtkContainerPeer.java | 138 + .../classpath/gnu/java/awt/peer/gtk/GtkCursor.java | 72 + .../gnu/java/awt/peer/gtk/GtkDialogPeer.java | 63 + .../java/awt/peer/gtk/GtkEmbeddedWindowPeer.java | 73 + .../gnu/java/awt/peer/gtk/GtkFileDialogPeer.java | 229 ++ .../gnu/java/awt/peer/gtk/GtkFramePeer.java | 254 ++ .../gnu/java/awt/peer/gtk/GtkGenericPeer.java | 145 ++ .../classpath/gnu/java/awt/peer/gtk/GtkImage.java | 541 ++++ .../gnu/java/awt/peer/gtk/GtkImageConsumer.java | 169 ++ .../gnu/java/awt/peer/gtk/GtkLabelPeer.java | 102 + .../gnu/java/awt/peer/gtk/GtkListPeer.java | 187 ++ .../gnu/java/awt/peer/gtk/GtkMainThread.java | 188 ++ .../gnu/java/awt/peer/gtk/GtkMenuBarPeer.java | 113 + .../java/awt/peer/gtk/GtkMenuComponentPeer.java | 104 + .../gnu/java/awt/peer/gtk/GtkMenuItemPeer.java | 116 + .../gnu/java/awt/peer/gtk/GtkMenuPeer.java | 126 + .../gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java | 65 + .../gnu/java/awt/peer/gtk/GtkPanelPeer.java | 67 + .../gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java | 68 + .../gnu/java/awt/peer/gtk/GtkScrollPanePeer.java | 111 + .../gnu/java/awt/peer/gtk/GtkScrollbarPeer.java | 92 + .../gnu/java/awt/peer/gtk/GtkSelection.java | 675 +++++ .../gnu/java/awt/peer/gtk/GtkTextAreaPeer.java | 223 ++ .../gnu/java/awt/peer/gtk/GtkTextFieldPeer.java | 200 ++ .../gnu/java/awt/peer/gtk/GtkToolkit.java | 766 ++++++ .../gnu/java/awt/peer/gtk/GtkVolatileImage.java | 207 ++ .../gnu/java/awt/peer/gtk/GtkWindowPeer.java | 437 ++++ .../java/awt/peer/gtk/VolatileImageGraphics.java | 325 +++ .../classpath/gnu/java/awt/peer/gtk/package.html | 46 + .../peer/headless/HeadlessGraphicsEnvironment.java | 118 + .../java/awt/peer/headless/HeadlessToolkit.java | 385 +++ libjava/classpath/gnu/java/awt/peer/package.html | 46 + .../gnu/java/awt/peer/qt/MainQtThread.java | 84 + .../gnu/java/awt/peer/qt/NativeWrapper.java | 43 + .../classpath/gnu/java/awt/peer/qt/QMatrix.java | 72 + .../gnu/java/awt/peer/qt/QPainterPath.java | 140 + libjava/classpath/gnu/java/awt/peer/qt/QPen.java | 70 + .../gnu/java/awt/peer/qt/QtAudioClip.java | 110 + .../gnu/java/awt/peer/qt/QtButtonPeer.java | 75 + .../gnu/java/awt/peer/qt/QtCanvasPeer.java | 65 + .../gnu/java/awt/peer/qt/QtCheckboxPeer.java | 111 + .../gnu/java/awt/peer/qt/QtChoicePeer.java | 93 + .../gnu/java/awt/peer/qt/QtComponentGraphics.java | 120 + .../gnu/java/awt/peer/qt/QtComponentPeer.java | 834 ++++++ .../gnu/java/awt/peer/qt/QtContainerPeer.java | 112 + .../gnu/java/awt/peer/qt/QtDialogPeer.java | 73 + .../gnu/java/awt/peer/qt/QtEmbeddedWindowPeer.java | 64 + .../gnu/java/awt/peer/qt/QtFileDialogPeer.java | 83 + .../gnu/java/awt/peer/qt/QtFontMetrics.java | 125 + .../classpath/gnu/java/awt/peer/qt/QtFontPeer.java | 197 ++ .../gnu/java/awt/peer/qt/QtFramePeer.java | 164 ++ .../classpath/gnu/java/awt/peer/qt/QtGraphics.java | 714 ++++++ .../java/awt/peer/qt/QtGraphicsEnvironment.java | 105 + .../classpath/gnu/java/awt/peer/qt/QtImage.java | 641 +++++ .../gnu/java/awt/peer/qt/QtImageConsumer.java | 147 ++ .../java/awt/peer/qt/QtImageDirectGraphics.java | 145 ++ .../gnu/java/awt/peer/qt/QtImageGraphics.java | 139 + .../gnu/java/awt/peer/qt/QtLabelPeer.java | 62 + .../classpath/gnu/java/awt/peer/qt/QtListPeer.java | 188 ++ .../gnu/java/awt/peer/qt/QtMenuBarPeer.java | 101 + .../gnu/java/awt/peer/qt/QtMenuComponentPeer.java | 94 + .../gnu/java/awt/peer/qt/QtMenuItemPeer.java | 100 + .../classpath/gnu/java/awt/peer/qt/QtMenuPeer.java | 149 ++ .../gnu/java/awt/peer/qt/QtPanelPeer.java | 56 + .../gnu/java/awt/peer/qt/QtPopupMenuPeer.java | 76 + .../gnu/java/awt/peer/qt/QtRepaintThread.java | 156 ++ .../gnu/java/awt/peer/qt/QtScreenDevice.java | 115 + .../awt/peer/qt/QtScreenDeviceConfiguration.java | 145 ++ .../gnu/java/awt/peer/qt/QtScrollPanePeer.java | 90 + .../gnu/java/awt/peer/qt/QtScrollbarPeer.java | 80 + .../gnu/java/awt/peer/qt/QtTextAreaPeer.java | 179 ++ .../gnu/java/awt/peer/qt/QtTextFieldPeer.java | 159 ++ .../classpath/gnu/java/awt/peer/qt/QtToolkit.java | 470 ++++ .../gnu/java/awt/peer/qt/QtVolatileImage.java | 434 ++++ .../gnu/java/awt/peer/qt/QtWindowPeer.java | 105 + .../gnu/java/awt/peer/swing/SwingButtonPeer.java | 261 ++ .../gnu/java/awt/peer/swing/SwingCanvasPeer.java | 64 + .../gnu/java/awt/peer/swing/SwingCheckboxPeer.java | 256 ++ .../gnu/java/awt/peer/swing/SwingComponent.java | 99 + .../java/awt/peer/swing/SwingComponentPeer.java | 1136 +++++++++ .../java/awt/peer/swing/SwingContainerPeer.java | 378 +++ .../gnu/java/awt/peer/swing/SwingFramePeer.java | 197 ++ .../gnu/java/awt/peer/swing/SwingLabelPeer.java | 242 ++ .../gnu/java/awt/peer/swing/SwingListPeer.java | 364 +++ .../gnu/java/awt/peer/swing/SwingMenuBarPeer.java | 295 +++ .../gnu/java/awt/peer/swing/SwingMenuItemPeer.java | 157 ++ .../gnu/java/awt/peer/swing/SwingMenuPeer.java | 284 +++ .../gnu/java/awt/peer/swing/SwingPanelPeer.java | 67 + .../gnu/java/awt/peer/swing/SwingTextAreaPeer.java | 487 ++++ .../java/awt/peer/swing/SwingTextFieldPeer.java | 411 +++ .../gnu/java/awt/peer/swing/SwingToolkit.java | 181 ++ .../gnu/java/awt/peer/swing/SwingWindowPeer.java | 99 + .../classpath/gnu/java/awt/peer/swing/package.html | 71 + .../classpath/gnu/java/awt/peer/x/GLGraphics.java | 134 + .../gnu/java/awt/peer/x/KeyboardMapping.java | 419 +++ .../gnu/java/awt/peer/x/PixmapVolatileImage.java | 185 ++ .../classpath/gnu/java/awt/peer/x/XDialogPeer.java | 61 + .../classpath/gnu/java/awt/peer/x/XEventPump.java | 486 ++++ .../classpath/gnu/java/awt/peer/x/XFontPeer.java | 770 ++++++ .../classpath/gnu/java/awt/peer/x/XFramePeer.java | 145 ++ .../classpath/gnu/java/awt/peer/x/XGraphics2D.java | 508 ++++ .../java/awt/peer/x/XGraphicsConfiguration.java | 200 ++ .../gnu/java/awt/peer/x/XGraphicsDevice.java | 200 ++ .../gnu/java/awt/peer/x/XGraphicsEnvironment.java | 203 ++ libjava/classpath/gnu/java/awt/peer/x/XImage.java | 178 ++ .../classpath/gnu/java/awt/peer/x/XToolkit.java | 667 +++++ .../classpath/gnu/java/awt/peer/x/XWindowPeer.java | 303 +++ .../gnu/java/awt/peer/x/ZPixmapDataBuffer.java | 67 + .../gnu/java/awt/print/JavaPrinterGraphics.java | 518 ++++ .../gnu/java/awt/print/JavaPrinterJob.java | 403 +++ .../gnu/java/awt/print/PostScriptGraphics2D.java | 1349 ++++++++++ .../gnu/java/awt/print/SpooledDocument.java | 90 + .../classpath/gnu/java/beans/BeanInfoEmbryo.java | 171 ++ .../gnu/java/beans/DefaultExceptionListener.java | 66 + .../gnu/java/beans/DummyAppletContext.java | 165 ++ .../classpath/gnu/java/beans/DummyAppletStub.java | 115 + .../classpath/gnu/java/beans/ExplicitBeanInfo.java | 149 ++ .../gnu/java/beans/IntrospectionIncubator.java | 441 ++++ libjava/classpath/gnu/java/beans/TODO | 1 + .../gnu/java/beans/decoder/AbstractContext.java | 70 + .../decoder/AbstractCreatableObjectContext.java | 113 + .../java/beans/decoder/AbstractElementHandler.java | 316 +++ .../java/beans/decoder/AbstractObjectContext.java | 127 + .../gnu/java/beans/decoder/ArrayContext.java | 122 + .../gnu/java/beans/decoder/ArrayHandler.java | 118 + .../gnu/java/beans/decoder/AssemblyException.java | 57 + .../gnu/java/beans/decoder/BooleanHandler.java | 67 + .../gnu/java/beans/decoder/ByteHandler.java | 59 + .../gnu/java/beans/decoder/CharHandler.java | 62 + .../gnu/java/beans/decoder/ClassHandler.java | 66 + .../gnu/java/beans/decoder/ConstructorContext.java | 102 + .../classpath/gnu/java/beans/decoder/Context.java | 137 + .../gnu/java/beans/decoder/DecoderContext.java | 124 + .../gnu/java/beans/decoder/DoubleHandler.java | 59 + .../gnu/java/beans/decoder/DummyContext.java | 116 + .../gnu/java/beans/decoder/DummyHandler.java | 156 ++ .../gnu/java/beans/decoder/ElementHandler.java | 130 + .../gnu/java/beans/decoder/FloatHandler.java | 59 + .../java/beans/decoder/GrowableArrayContext.java | 138 + .../gnu/java/beans/decoder/IndexContext.java | 130 + .../gnu/java/beans/decoder/IntHandler.java | 59 + .../gnu/java/beans/decoder/JavaHandler.java | 93 + .../gnu/java/beans/decoder/LongHandler.java | 59 + .../gnu/java/beans/decoder/MethodContext.java | 107 + .../gnu/java/beans/decoder/MethodFinder.java | 177 ++ .../gnu/java/beans/decoder/NullHandler.java | 62 + .../gnu/java/beans/decoder/ObjectContext.java | 100 + .../gnu/java/beans/decoder/ObjectHandler.java | 169 ++ .../gnu/java/beans/decoder/PersistenceParser.java | 485 ++++ .../gnu/java/beans/decoder/PropertyContext.java | 137 + .../gnu/java/beans/decoder/ShortHandler.java | 58 + .../gnu/java/beans/decoder/SimpleHandler.java | 111 + .../java/beans/decoder/StaticMethodContext.java | 95 + .../gnu/java/beans/decoder/StringHandler.java | 54 + .../gnu/java/beans/decoder/VoidHandler.java | 140 + .../classpath/gnu/java/beans/decoder/package.html | 46 + .../gnu/java/beans/editors/ColorEditor.java | 100 + .../gnu/java/beans/editors/FontEditor.java | 77 + .../java/beans/editors/NativeBooleanEditor.java | 76 + .../gnu/java/beans/editors/NativeByteEditor.java | 61 + .../gnu/java/beans/editors/NativeDoubleEditor.java | 61 + .../gnu/java/beans/editors/NativeFloatEditor.java | 61 + .../gnu/java/beans/editors/NativeIntEditor.java | 61 + .../gnu/java/beans/editors/NativeLongEditor.java | 61 + .../gnu/java/beans/editors/NativeShortEditor.java | 61 + .../gnu/java/beans/editors/StringEditor.java | 61 + libjava/classpath/gnu/java/beans/editors/TODO | 4 + .../classpath/gnu/java/beans/editors/package.html | 46 + .../beans/encoder/ArrayPersistenceDelegate.java | 153 ++ .../beans/encoder/ClassPersistenceDelegate.java | 80 + .../encoder/CollectionPersistenceDelegate.java | 84 + .../classpath/gnu/java/beans/encoder/Context.java | 88 + .../java/beans/encoder/GenericScannerState.java | 257 ++ .../java/beans/encoder/IgnoringScannerState.java | 133 + .../java/beans/encoder/MapPersistenceDelegate.java | 81 + .../classpath/gnu/java/beans/encoder/ObjectId.java | 132 + .../encoder/PrimitivePersistenceDelegate.java | 74 + .../java/beans/encoder/ReportingScannerState.java | 131 + libjava/classpath/gnu/java/beans/encoder/Root.java | 198 ++ .../gnu/java/beans/encoder/ScanEngine.java | 860 +++++++ .../gnu/java/beans/encoder/ScannerState.java | 236 ++ .../gnu/java/beans/encoder/StAXWriter.java | 233 ++ .../classpath/gnu/java/beans/encoder/Writer.java | 174 ++ .../beans/encoder/elements/ArrayInstantiation.java | 74 + .../gnu/java/beans/encoder/elements/Array_Get.java | 62 + .../gnu/java/beans/encoder/elements/Array_Set.java | 57 + .../beans/encoder/elements/ClassResolution.java | 67 + .../gnu/java/beans/encoder/elements/Element.java | 157 ++ .../gnu/java/beans/encoder/elements/List_Get.java | 56 + .../gnu/java/beans/encoder/elements/List_Set.java | 56 + .../beans/encoder/elements/MethodInvocation.java | 62 + .../java/beans/encoder/elements/NullObject.java | 61 + .../encoder/elements/ObjectInstantiation.java | 68 + .../beans/encoder/elements/ObjectReference.java | 68 + .../encoder/elements/PrimitiveInstantiation.java | 69 + .../beans/encoder/elements/StaticFieldAccess.java | 66 + .../encoder/elements/StaticMethodInvocation.java | 67 + .../beans/encoder/elements/StringReference.java | 63 + libjava/classpath/gnu/java/beans/package.html | 46 + .../gnu/java/io/ASN1ParsingException.java | 56 + .../classpath/gnu/java/io/Base64InputStream.java | 220 ++ .../gnu/java/io/ClassLoaderObjectInputStream.java | 73 + .../classpath/gnu/java/io/NullOutputStream.java | 56 + .../gnu/java/io/ObjectIdentityMap2Int.java | 292 +++ .../gnu/java/io/ObjectIdentityWrapper.java | 100 + libjava/classpath/gnu/java/io/PlatformHelper.java | 129 + libjava/classpath/gnu/java/io/package.html | 46 + libjava/classpath/gnu/java/lang/ArrayHelper.java | 78 + .../classpath/gnu/java/lang/CPStringBuilder.java | 1161 +++++++++ libjava/classpath/gnu/java/lang/CharData.java | 1705 +++++++++++++ libjava/classpath/gnu/java/lang/ClassHelper.java | 205 ++ .../gnu/java/lang/InstrumentationImpl.java | 241 ++ libjava/classpath/gnu/java/lang/MainThread.java | 83 + .../gnu/java/lang/management/BeanImpl.java | 447 ++++ .../lang/management/ClassLoadingMXBeanImpl.java | 98 + .../lang/management/CompilationMXBeanImpl.java | 105 + .../management/GarbageCollectorMXBeanImpl.java | 84 + .../gnu/java/lang/management/MemoryMXBeanImpl.java | 281 ++ .../lang/management/MemoryManagerMXBeanImpl.java | 112 + .../java/lang/management/MemoryPoolMXBeanImpl.java | 226 ++ .../lang/management/OperatingSystemMXBeanImpl.java | 95 + .../java/lang/management/RuntimeMXBeanImpl.java | 197 ++ .../gnu/java/lang/management/ThreadMXBeanImpl.java | 350 +++ .../gnu/java/lang/management/package.html | 46 + libjava/classpath/gnu/java/lang/package.html | 46 + .../java/lang/reflect/ClassSignatureParser.java | 92 + .../java/lang/reflect/FieldSignatureParser.java | 103 + .../java/lang/reflect/GenericSignatureParser.java | 631 +++++ .../java/lang/reflect/MethodSignatureParser.java | 167 ++ .../classpath/gnu/java/lang/reflect/TypeImpl.java | 63 + .../gnu/java/lang/reflect/TypeSignature.java | 290 +++ .../classpath/gnu/java/lang/reflect/package.html | 46 + libjava/classpath/gnu/java/locale/.cvsignore | 1 + .../classpath/gnu/java/locale/LocaleHelper.java | 147 ++ libjava/classpath/gnu/java/locale/package.html | 46 + libjava/classpath/gnu/java/math/Fixed.java | 220 ++ libjava/classpath/gnu/java/math/GMP.java | 474 ++++ libjava/classpath/gnu/java/math/MPN.java | 771 ++++++ libjava/classpath/gnu/java/math/package.html | 46 + .../classpath/gnu/java/net/CRLFInputStream.java | 178 ++ .../classpath/gnu/java/net/CRLFOutputStream.java | 182 ++ .../gnu/java/net/DefaultContentHandlerFactory.java | 94 + .../gnu/java/net/DefaultProxySelector.java | 80 + .../gnu/java/net/EmptyX509TrustManager.java | 69 + .../classpath/gnu/java/net/GetLocalHostAction.java | 64 + .../classpath/gnu/java/net/HeaderFieldHelper.java | 136 + .../classpath/gnu/java/net/IndexListParser.java | 183 ++ .../classpath/gnu/java/net/LineInputStream.java | 223 ++ .../gnu/java/net/PlainDatagramSocketImpl.java | 486 ++++ .../classpath/gnu/java/net/PlainSocketImpl.java | 678 +++++ libjava/classpath/gnu/java/net/URLParseError.java | 57 + .../gnu/java/net/loader/FileResource.java | 82 + .../gnu/java/net/loader/FileURLLoader.java | 145 ++ .../gnu/java/net/loader/JarURLLoader.java | 215 ++ .../gnu/java/net/loader/JarURLResource.java | 94 + .../gnu/java/net/loader/RemoteResource.java | 78 + .../gnu/java/net/loader/RemoteURLLoader.java | 101 + .../classpath/gnu/java/net/loader/Resource.java | 110 + .../classpath/gnu/java/net/loader/URLLoader.java | 148 ++ .../gnu/java/net/loader/URLStreamHandlerCache.java | 85 + .../gnu/java/net/local/LocalServerSocket.java | 171 ++ .../classpath/gnu/java/net/local/LocalSocket.java | 312 +++ .../gnu/java/net/local/LocalSocketAddress.java | 100 + .../gnu/java/net/local/LocalSocketImpl.java | 334 +++ libjava/classpath/gnu/java/net/package.html | 46 + .../gnu/java/net/protocol/file/Connection.java | 376 +++ .../gnu/java/net/protocol/file/Handler.java | 91 + .../gnu/java/net/protocol/file/package.html | 46 + .../gnu/java/net/protocol/ftp/ActiveModeDTP.java | 251 ++ .../java/net/protocol/ftp/BlockInputStream.java | 149 ++ .../java/net/protocol/ftp/BlockOutputStream.java | 110 + .../net/protocol/ftp/CompressedInputStream.java | 214 ++ .../net/protocol/ftp/CompressedOutputStream.java | 227 ++ .../classpath/gnu/java/net/protocol/ftp/DTP.java | 91 + .../gnu/java/net/protocol/ftp/DTPInputStream.java | 87 + .../gnu/java/net/protocol/ftp/DTPOutputStream.java | 85 + .../gnu/java/net/protocol/ftp/FTPConnection.java | 1352 ++++++++++ .../gnu/java/net/protocol/ftp/FTPException.java | 75 + .../gnu/java/net/protocol/ftp/FTPResponse.java | 111 + .../java/net/protocol/ftp/FTPURLConnection.java | 375 +++ .../gnu/java/net/protocol/ftp/Handler.java | 69 + .../gnu/java/net/protocol/ftp/PassiveModeDTP.java | 200 ++ .../java/net/protocol/ftp/StreamInputStream.java | 94 + .../java/net/protocol/ftp/StreamOutputStream.java | 84 + .../gnu/java/net/protocol/ftp/package.html | 60 + .../gnu/java/net/protocol/http/Authenticator.java | 58 + .../protocol/http/ByteArrayRequestBodyWriter.java | 106 + .../java/net/protocol/http/ChunkedInputStream.java | 223 ++ .../gnu/java/net/protocol/http/Cookie.java | 161 ++ .../gnu/java/net/protocol/http/CookieManager.java | 65 + .../gnu/java/net/protocol/http/Credentials.java | 87 + .../gnu/java/net/protocol/http/HTTPConnection.java | 897 +++++++ .../gnu/java/net/protocol/http/HTTPDateFormat.java | 440 ++++ .../java/net/protocol/http/HTTPURLConnection.java | 693 +++++ .../gnu/java/net/protocol/http/Handler.java | 72 + .../gnu/java/net/protocol/http/Headers.java | 424 ++++ .../protocol/http/LimitedLengthInputStream.java | 216 ++ .../gnu/java/net/protocol/http/Request.java | 857 +++++++ .../java/net/protocol/http/RequestBodyWriter.java | 68 + .../gnu/java/net/protocol/http/Response.java | 223 ++ .../net/protocol/http/ResponseHeaderHandler.java | 56 + .../net/protocol/http/SimpleCookieManager.java | 137 + .../gnu/java/net/protocol/http/package.html | 76 + .../gnu/java/net/protocol/https/Handler.java | 75 + .../gnu/java/net/protocol/jar/Connection.java | 232 ++ .../gnu/java/net/protocol/jar/Handler.java | 217 ++ .../gnu/java/net/protocol/jar/package.html | 46 + .../classpath/gnu/java/nio/ChannelInputStream.java | 89 + .../gnu/java/nio/ChannelOutputStream.java | 67 + libjava/classpath/gnu/java/nio/ChannelReader.java | 217 ++ libjava/classpath/gnu/java/nio/ChannelWriter.java | 190 ++ .../gnu/java/nio/DatagramChannelImpl.java | 240 ++ .../gnu/java/nio/DatagramChannelSelectionKey.java | 68 + .../gnu/java/nio/EpollSelectionKeyImpl.java | 122 + .../classpath/gnu/java/nio/EpollSelectorImpl.java | 399 +++ .../classpath/gnu/java/nio/FileChannelImpl.java | 572 +++++ libjava/classpath/gnu/java/nio/FileLockImpl.java | 102 + .../classpath/gnu/java/nio/InputStreamChannel.java | 88 + .../gnu/java/nio/KqueueSelectionKeyImpl.java | 187 ++ .../classpath/gnu/java/nio/KqueueSelectorImpl.java | 527 ++++ libjava/classpath/gnu/java/nio/NIOConstants.java | 47 + .../classpath/gnu/java/nio/NIODatagramSocket.java | 71 + .../classpath/gnu/java/nio/NIOServerSocket.java | 106 + libjava/classpath/gnu/java/nio/NIOSocket.java | 79 + libjava/classpath/gnu/java/nio/NIOSocketImpl.java | 110 + .../gnu/java/nio/OutputStreamChannel.java | 87 + libjava/classpath/gnu/java/nio/PipeImpl.java | 178 ++ .../classpath/gnu/java/nio/SelectionKeyImpl.java | 111 + libjava/classpath/gnu/java/nio/SelectorImpl.java | 397 +++ .../gnu/java/nio/SelectorProviderImpl.java | 121 + .../gnu/java/nio/ServerSocketChannelImpl.java | 128 + .../java/nio/ServerSocketChannelSelectionKey.java | 65 + .../classpath/gnu/java/nio/SocketChannelImpl.java | 265 ++ .../gnu/java/nio/SocketChannelSelectionKey.java | 65 + .../java/nio/SocketChannelSelectionKeyImpl.java | 78 + libjava/classpath/gnu/java/nio/VMChannelOwner.java | 57 + .../classpath/gnu/java/nio/channels/package.html | 46 + .../gnu/java/nio/charset/ByteCharset.java | 193 ++ .../gnu/java/nio/charset/ByteDecodeLoopHelper.java | 164 ++ .../gnu/java/nio/charset/ByteEncodeLoopHelper.java | 165 ++ libjava/classpath/gnu/java/nio/charset/Cp424.java | 86 + libjava/classpath/gnu/java/nio/charset/Cp437.java | 87 + libjava/classpath/gnu/java/nio/charset/Cp737.java | 87 + libjava/classpath/gnu/java/nio/charset/Cp775.java | 87 + libjava/classpath/gnu/java/nio/charset/Cp850.java | 87 + libjava/classpath/gnu/java/nio/charset/Cp852.java | 87 + libjava/classpath/gnu/java/nio/charset/Cp855.java | 87 + libjava/classpath/gnu/java/nio/charset/Cp857.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp860.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp861.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp862.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp863.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp864.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp865.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp866.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp869.java | 88 + libjava/classpath/gnu/java/nio/charset/Cp874.java | 87 + .../gnu/java/nio/charset/EncodingHelper.java | 161 ++ .../classpath/gnu/java/nio/charset/ISO_8859_1.java | 165 ++ .../gnu/java/nio/charset/ISO_8859_13.java | 102 + .../gnu/java/nio/charset/ISO_8859_15.java | 109 + .../classpath/gnu/java/nio/charset/ISO_8859_2.java | 108 + .../classpath/gnu/java/nio/charset/ISO_8859_3.java | 107 + .../classpath/gnu/java/nio/charset/ISO_8859_4.java | 108 + .../classpath/gnu/java/nio/charset/ISO_8859_5.java | 106 + .../classpath/gnu/java/nio/charset/ISO_8859_6.java | 110 + .../classpath/gnu/java/nio/charset/ISO_8859_7.java | 109 + .../classpath/gnu/java/nio/charset/ISO_8859_8.java | 108 + .../classpath/gnu/java/nio/charset/ISO_8859_9.java | 108 + libjava/classpath/gnu/java/nio/charset/KOI_8.java | 100 + libjava/classpath/gnu/java/nio/charset/MS874.java | 87 + .../gnu/java/nio/charset/MacCentralEurope.java | 87 + .../gnu/java/nio/charset/MacCroatian.java | 87 + .../gnu/java/nio/charset/MacCyrillic.java | 87 + .../classpath/gnu/java/nio/charset/MacDingbat.java | 87 + .../classpath/gnu/java/nio/charset/MacGreek.java | 87 + .../classpath/gnu/java/nio/charset/MacIceland.java | 87 + .../classpath/gnu/java/nio/charset/MacRoman.java | 87 + .../classpath/gnu/java/nio/charset/MacRomania.java | 87 + .../classpath/gnu/java/nio/charset/MacSymbol.java | 87 + .../classpath/gnu/java/nio/charset/MacThai.java | 87 + .../classpath/gnu/java/nio/charset/MacTurkish.java | 87 + .../classpath/gnu/java/nio/charset/Provider.java | 271 ++ .../classpath/gnu/java/nio/charset/US_ASCII.java | 162 ++ libjava/classpath/gnu/java/nio/charset/UTF_16.java | 80 + .../classpath/gnu/java/nio/charset/UTF_16BE.java | 84 + .../gnu/java/nio/charset/UTF_16Decoder.java | 167 ++ .../gnu/java/nio/charset/UTF_16Encoder.java | 145 ++ .../classpath/gnu/java/nio/charset/UTF_16LE.java | 83 + libjava/classpath/gnu/java/nio/charset/UTF_8.java | 311 +++ .../gnu/java/nio/charset/UnicodeLittle.java | 74 + .../gnu/java/nio/charset/Windows1250.java | 101 + .../gnu/java/nio/charset/Windows1251.java | 99 + .../gnu/java/nio/charset/Windows1252.java | 98 + .../gnu/java/nio/charset/Windows1253.java | 99 + .../gnu/java/nio/charset/Windows1254.java | 99 + .../gnu/java/nio/charset/Windows1255.java | 99 + .../gnu/java/nio/charset/Windows1256.java | 99 + .../gnu/java/nio/charset/Windows1257.java | 99 + .../gnu/java/nio/charset/Windows1258.java | 99 + .../gnu/java/nio/charset/iconv/IconvCharset.java | 85 + .../gnu/java/nio/charset/iconv/IconvDecoder.java | 110 + .../gnu/java/nio/charset/iconv/IconvEncoder.java | 110 + .../gnu/java/nio/charset/iconv/IconvMetaData.java | 450 ++++ .../gnu/java/nio/charset/iconv/IconvProvider.java | 110 + .../classpath/gnu/java/nio/charset/package.html | 46 + libjava/classpath/gnu/java/nio/package.html | 46 + .../java/rmi/RMIMarshalledObjectInputStream.java | 71 + .../java/rmi/RMIMarshalledObjectOutputStream.java | 78 + .../rmi/activation/ActivationSystemTransient.java | 406 +++ .../gnu/java/rmi/activation/BidiTable.java | 163 ++ .../rmi/activation/DefaultActivationGroup.java | 159 ++ .../rmi/activation/DefaultActivationSystem.java | 118 + libjava/classpath/gnu/java/rmi/dgc/DGCImpl.java | 182 ++ .../classpath/gnu/java/rmi/dgc/DGCImpl_Skel.java | 144 ++ .../classpath/gnu/java/rmi/dgc/DGCImpl_Stub.java | 158 ++ .../gnu/java/rmi/dgc/LeaseRenewingTask.java | 234 ++ libjava/classpath/gnu/java/rmi/dgc/package.html | 46 + libjava/classpath/gnu/java/rmi/package.html | 46 + .../gnu/java/rmi/registry/RegistryImpl.java | 154 ++ .../gnu/java/rmi/registry/RegistryImpl_Skel.java | 227 ++ .../gnu/java/rmi/registry/RegistryImpl_Stub.java | 293 +++ .../classpath/gnu/java/rmi/registry/package.html | 46 + .../gnu/java/rmi/server/ActivatableRef.java | 179 ++ .../gnu/java/rmi/server/ActivatableServerRef.java | 227 ++ .../gnu/java/rmi/server/CombinedClassLoader.java | 135 + .../gnu/java/rmi/server/ConnectionRunnerPool.java | 156 ++ .../gnu/java/rmi/server/ProtocolConstants.java | 62 + .../gnu/java/rmi/server/RMIClassLoaderImpl.java | 357 +++ .../java/rmi/server/RMIDefaultSocketFactory.java | 59 + .../classpath/gnu/java/rmi/server/RMIHashes.java | 99 + .../gnu/java/rmi/server/RMIIncomingThread.java | 58 + .../gnu/java/rmi/server/RMIObjectInputStream.java | 118 + .../gnu/java/rmi/server/RMIObjectOutputStream.java | 114 + .../gnu/java/rmi/server/RMIVoidValue.java | 51 + .../gnu/java/rmi/server/UnicastConnection.java | 231 ++ .../java/rmi/server/UnicastConnectionManager.java | 468 ++++ .../classpath/gnu/java/rmi/server/UnicastRef.java | 524 ++++ .../gnu/java/rmi/server/UnicastRemoteCall.java | 525 ++++ .../gnu/java/rmi/server/UnicastRemoteStub.java | 50 + .../gnu/java/rmi/server/UnicastServer.java | 321 +++ .../gnu/java/rmi/server/UnicastServerRef.java | 481 ++++ libjava/classpath/gnu/java/rmi/server/package.html | 46 + libjava/classpath/gnu/java/security/.cvsignore | 1 + .../gnu/java/security/Configuration.java.in | 56 + libjava/classpath/gnu/java/security/Engine.java | 282 +++ libjava/classpath/gnu/java/security/OID.java | 512 ++++ .../classpath/gnu/java/security/PolicyFile.java | 687 +++++ .../classpath/gnu/java/security/Properties.java | 348 +++ libjava/classpath/gnu/java/security/Registry.java | 465 ++++ libjava/classpath/gnu/java/security/Requires.java | 59 + .../java/security/action/GetPropertyAction.java | 89 + .../security/action/GetSecurityPropertyAction.java | 93 + .../java/security/action/SetAccessibleAction.java | 77 + .../gnu/java/security/action/package.html | 46 + libjava/classpath/gnu/java/security/ber/BER.java | 46 + .../java/security/ber/BEREncodingException.java | 54 + .../classpath/gnu/java/security/ber/BERReader.java | 103 + .../classpath/gnu/java/security/ber/BERValue.java | 82 + .../classpath/gnu/java/security/ber/package.html | 46 + .../classpath/gnu/java/security/der/BitString.java | 332 +++ libjava/classpath/gnu/java/security/der/DER.java | 86 + .../java/security/der/DEREncodingException.java | 54 + .../classpath/gnu/java/security/der/DERReader.java | 439 ++++ .../classpath/gnu/java/security/der/DERValue.java | 189 ++ .../classpath/gnu/java/security/der/DERWriter.java | 355 +++ .../classpath/gnu/java/security/der/package.html | 46 + .../classpath/gnu/java/security/hash/BaseHash.java | 183 ++ .../gnu/java/security/hash/HashFactory.java | 135 + .../classpath/gnu/java/security/hash/Haval.java | 807 ++++++ .../gnu/java/security/hash/IMessageDigest.java | 127 + libjava/classpath/gnu/java/security/hash/MD2.java | 256 ++ libjava/classpath/gnu/java/security/hash/MD4.java | 337 +++ libjava/classpath/gnu/java/security/hash/MD5.java | 371 +++ .../gnu/java/security/hash/RipeMD128.java | 257 ++ .../gnu/java/security/hash/RipeMD160.java | 291 +++ .../classpath/gnu/java/security/hash/Sha160.java | 241 ++ .../classpath/gnu/java/security/hash/Sha256.java | 252 ++ .../classpath/gnu/java/security/hash/Sha384.java | 279 ++ .../classpath/gnu/java/security/hash/Sha512.java | 281 ++ .../classpath/gnu/java/security/hash/Tiger.java | 864 +++++++ .../gnu/java/security/hash/Whirlpool.java | 608 +++++ .../gnu/java/security/jce/hash/HavalSpi.java | 54 + .../gnu/java/security/jce/hash/MD2Spi.java | 55 + .../gnu/java/security/jce/hash/MD4Spi.java | 55 + .../gnu/java/security/jce/hash/MD5Spi.java | 54 + .../security/jce/hash/MessageDigestAdapter.java | 133 + .../gnu/java/security/jce/hash/RipeMD128Spi.java | 54 + .../gnu/java/security/jce/hash/RipeMD160Spi.java | 54 + .../gnu/java/security/jce/hash/Sha160Spi.java | 54 + .../gnu/java/security/jce/hash/Sha256Spi.java | 54 + .../gnu/java/security/jce/hash/Sha384Spi.java | 54 + .../gnu/java/security/jce/hash/Sha512Spi.java | 54 + .../gnu/java/security/jce/hash/TigerSpi.java | 55 + .../gnu/java/security/jce/hash/WhirlpoolSpi.java | 54 + .../gnu/java/security/jce/prng/HavalRandomSpi.java | 54 + .../gnu/java/security/jce/prng/MD2RandomSpi.java | 54 + .../gnu/java/security/jce/prng/MD4RandomSpi.java | 54 + .../gnu/java/security/jce/prng/MD5RandomSpi.java | 54 + .../java/security/jce/prng/RipeMD128RandomSpi.java | 54 + .../java/security/jce/prng/RipeMD160RandomSpi.java | 54 + .../security/jce/prng/SecureRandomAdapter.java | 184 ++ .../java/security/jce/prng/Sha160RandomSpi.java | 54 + .../java/security/jce/prng/Sha256RandomSpi.java | 54 + .../java/security/jce/prng/Sha384RandomSpi.java | 54 + .../java/security/jce/prng/Sha512RandomSpi.java | 54 + .../gnu/java/security/jce/prng/TigerRandomSpi.java | 54 + .../java/security/jce/prng/WhirlpoolRandomSpi.java | 54 + .../gnu/java/security/jce/sig/DSSKeyFactory.java | 221 ++ .../security/jce/sig/DSSKeyPairGeneratorSpi.java | 146 ++ .../gnu/java/security/jce/sig/DSSParameters.java | 220 ++ .../security/jce/sig/DSSParametersGenerator.java | 125 + .../java/security/jce/sig/DSSRawSignatureSpi.java | 56 + .../java/security/jce/sig/EncodedKeyFactory.java | 430 ++++ .../security/jce/sig/KeyPairGeneratorAdapter.java | 95 + .../gnu/java/security/jce/sig/MD2withRSA.java | 56 + .../gnu/java/security/jce/sig/MD5withRSA.java | 56 + .../gnu/java/security/jce/sig/RSAKeyFactory.java | 231 ++ .../security/jce/sig/RSAKeyPairGeneratorSpi.java | 96 + .../security/jce/sig/RSAPSSRawSignatureSpi.java | 56 + .../gnu/java/security/jce/sig/SHA160withDSS.java | 54 + .../gnu/java/security/jce/sig/SHA160withRSA.java | 56 + .../gnu/java/security/jce/sig/SHA256withRSA.java | 56 + .../gnu/java/security/jce/sig/SHA384withRSA.java | 56 + .../gnu/java/security/jce/sig/SHA512withRSA.java | 56 + .../java/security/jce/sig/SignatureAdapter.java | 250 ++ .../gnu/java/security/key/IKeyPairCodec.java | 124 + .../gnu/java/security/key/IKeyPairGenerator.java | 73 + .../gnu/java/security/key/KeyPairCodecFactory.java | 360 +++ .../java/security/key/KeyPairGeneratorFactory.java | 120 + .../gnu/java/security/key/dss/DSSKey.java | 213 ++ .../java/security/key/dss/DSSKeyPairGenerator.java | 382 +++ .../security/key/dss/DSSKeyPairPKCS8Codec.java | 249 ++ .../java/security/key/dss/DSSKeyPairRawCodec.java | 347 +++ .../java/security/key/dss/DSSKeyPairX509Codec.java | 276 ++ .../gnu/java/security/key/dss/DSSPrivateKey.java | 205 ++ .../gnu/java/security/key/dss/DSSPublicKey.java | 203 ++ .../gnu/java/security/key/dss/FIPS186.java | 262 ++ .../gnu/java/security/key/rsa/GnuRSAKey.java | 178 ++ .../java/security/key/rsa/GnuRSAPrivateKey.java | 313 +++ .../gnu/java/security/key/rsa/GnuRSAPublicKey.java | 190 ++ .../java/security/key/rsa/RSAKeyPairGenerator.java | 246 ++ .../security/key/rsa/RSAKeyPairPKCS8Codec.java | 299 +++ .../java/security/key/rsa/RSAKeyPairRawCodec.java | 300 +++ .../java/security/key/rsa/RSAKeyPairX509Codec.java | 250 ++ libjava/classpath/gnu/java/security/package.html | 46 + .../gnu/java/security/pkcs/PKCS7Data.java | 69 + .../gnu/java/security/pkcs/PKCS7SignedData.java | 485 ++++ .../gnu/java/security/pkcs/SignerInfo.java | 429 ++++ .../classpath/gnu/java/security/pkcs/package.html | 46 + .../classpath/gnu/java/security/prng/BasePRNG.java | 178 ++ .../gnu/java/security/prng/EntropySource.java | 61 + .../classpath/gnu/java/security/prng/IRandom.java | 174 ++ .../java/security/prng/LimitReachedException.java | 57 + .../gnu/java/security/prng/MDGenerator.java | 127 + .../gnu/java/security/prng/PRNGFactory.java | 92 + .../gnu/java/security/prng/RandomEvent.java | 81 + .../java/security/prng/RandomEventListener.java | 50 + .../security/provider/CollectionCertStoreImpl.java | 102 + .../gnu/java/security/provider/DefaultPolicy.java | 68 + .../classpath/gnu/java/security/provider/Gnu.java | 306 +++ .../provider/PKIXCertPathValidatorImpl.java | 693 +++++ .../security/provider/X509CertificateFactory.java | 295 +++ .../gnu/java/security/provider/package.html | 46 + .../gnu/java/security/sig/BaseSignature.java | 219 ++ .../gnu/java/security/sig/ISignature.java | 160 ++ .../gnu/java/security/sig/ISignatureCodec.java | 59 + .../java/security/sig/SignatureCodecFactory.java | 226 ++ .../gnu/java/security/sig/SignatureFactory.java | 101 + .../gnu/java/security/sig/dss/DSSSignature.java | 275 ++ .../security/sig/dss/DSSSignatureRawCodec.java | 164 ++ .../security/sig/dss/DSSSignatureX509Codec.java | 193 ++ .../gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java | 274 ++ .../gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java | 243 ++ .../gnu/java/security/sig/rsa/EMSA_PSS.java | 371 +++ .../classpath/gnu/java/security/sig/rsa/RSA.java | 324 +++ .../security/sig/rsa/RSAPKCS1V1_5Signature.java | 224 ++ .../sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java | 153 ++ .../sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java | 128 + .../gnu/java/security/sig/rsa/RSAPSSSignature.java | 255 ++ .../security/sig/rsa/RSAPSSSignatureRawCodec.java | 134 + .../java/security/sig/rsa/RSASignatureFactory.java | 176 ++ .../gnu/java/security/util/ByteArray.java | 111 + .../java/security/util/ByteBufferOutputStream.java | 118 + .../classpath/gnu/java/security/util/DerUtil.java | 64 + .../gnu/java/security/util/ExpirableObject.java | 150 ++ .../gnu/java/security/util/FormatUtil.java | 140 + .../gnu/java/security/util/IntegerUtil.java | 109 + libjava/classpath/gnu/java/security/util/PRNG.java | 141 ++ .../classpath/gnu/java/security/util/Prime.java | 164 ++ .../classpath/gnu/java/security/util/Sequence.java | 133 + .../gnu/java/security/util/SimpleList.java | 155 ++ libjava/classpath/gnu/java/security/util/Util.java | 629 +++++ .../classpath/gnu/java/security/util/package.html | 46 + .../gnu/java/security/x509/GnuPKIExtension.java | 59 + .../gnu/java/security/x509/PolicyNodeImpl.java | 216 ++ libjava/classpath/gnu/java/security/x509/Util.java | 204 ++ .../java/security/x509/X500DistinguishedName.java | 558 ++++ .../classpath/gnu/java/security/x509/X509CRL.java | 485 ++++ .../gnu/java/security/x509/X509CRLEntry.java | 273 ++ .../java/security/x509/X509CRLSelectorImpl.java | 137 + .../gnu/java/security/x509/X509CertPath.java | 303 +++ .../java/security/x509/X509CertSelectorImpl.java | 196 ++ .../gnu/java/security/x509/X509Certificate.java | 757 ++++++ .../security/x509/ext/AuthorityKeyIdentifier.java | 133 + .../java/security/x509/ext/BasicConstraints.java | 129 + .../gnu/java/security/x509/ext/CRLNumber.java | 97 + .../security/x509/ext/CertificatePolicies.java | 205 ++ .../java/security/x509/ext/ExtendedKeyUsage.java | 95 + .../gnu/java/security/x509/ext/Extension.java | 297 +++ .../gnu/java/security/x509/ext/GeneralName.java | 232 ++ .../gnu/java/security/x509/ext/GeneralNames.java | 89 + .../gnu/java/security/x509/ext/GeneralSubtree.java | 156 ++ .../security/x509/ext/IssuerAlternativeNames.java | 77 + .../gnu/java/security/x509/ext/KeyUsage.java | 92 + .../java/security/x509/ext/NameConstraints.java | 161 ++ .../java/security/x509/ext/PolicyConstraint.java | 107 + .../gnu/java/security/x509/ext/PolicyMappings.java | 104 + .../security/x509/ext/PrivateKeyUsagePeriod.java | 105 + .../gnu/java/security/x509/ext/ReasonCode.java | 85 + .../security/x509/ext/SubjectAlternativeNames.java | 77 + .../security/x509/ext/SubjectKeyIdentifier.java | 84 + .../gnu/java/security/x509/ext/package.html | 46 + .../classpath/gnu/java/security/x509/package.html | 46 + .../gnu/java/text/AttributedFormatBuffer.java | 251 ++ .../classpath/gnu/java/text/BaseBreakIterator.java | 124 + .../gnu/java/text/CharacterBreakIterator.java | 213 ++ libjava/classpath/gnu/java/text/FormatBuffer.java | 136 + .../gnu/java/text/FormatCharacterIterator.java | 533 ++++ .../classpath/gnu/java/text/LineBreakIterator.java | 194 ++ .../gnu/java/text/SentenceBreakIterator.java | 247 ++ .../gnu/java/text/StringFormatBuffer.java | 127 + .../classpath/gnu/java/text/WordBreakIterator.java | 250 ++ libjava/classpath/gnu/java/text/package.html | 46 + libjava/classpath/gnu/java/util/Base64.java | 342 +++ .../classpath/gnu/java/util/DoubleEnumeration.java | 138 + .../classpath/gnu/java/util/EmptyEnumeration.java | 90 + libjava/classpath/gnu/java/util/LRUCache.java | 77 + .../gnu/java/util/WeakIdentityHashMap.java | 862 +++++++ libjava/classpath/gnu/java/util/ZoneInfo.java | 1160 +++++++++ libjava/classpath/gnu/java/util/jar/JarUtils.java | 451 ++++ libjava/classpath/gnu/java/util/package.html | 46 + .../gnu/java/util/prefs/FileBasedFactory.java | 65 + .../gnu/java/util/prefs/FileBasedPreferences.java | 273 ++ .../gnu/java/util/prefs/GConfBasedFactory.java | 78 + .../gnu/java/util/prefs/GConfBasedPreferences.java | 419 +++ .../gnu/java/util/prefs/MemoryBasedFactory.java | 64 + .../java/util/prefs/MemoryBasedPreferences.java | 144 ++ .../classpath/gnu/java/util/prefs/NodeReader.java | 221 ++ .../classpath/gnu/java/util/prefs/NodeWriter.java | 319 +++ .../gnu/java/util/prefs/gconf/GConfNativePeer.java | 286 +++ libjava/classpath/gnu/java/util/prefs/package.html | 46 + .../gnu/java/util/regex/BacktrackStack.java | 124 + .../classpath/gnu/java/util/regex/CharIndexed.java | 134 + .../gnu/java/util/regex/CharIndexedCharArray.java | 48 + .../java/util/regex/CharIndexedCharSequence.java | 119 + .../java/util/regex/CharIndexedInputStream.java | 253 ++ .../gnu/java/util/regex/CharIndexedString.java | 46 + .../java/util/regex/CharIndexedStringBuffer.java | 47 + libjava/classpath/gnu/java/util/regex/RE.java | 2675 ++++++++++++++++++++ .../classpath/gnu/java/util/regex/REException.java | 198 ++ .../gnu/java/util/regex/REFilterInputStream.java | 153 ++ libjava/classpath/gnu/java/util/regex/REMatch.java | 362 +++ .../gnu/java/util/regex/REMatchEnumeration.java | 141 ++ .../classpath/gnu/java/util/regex/RESyntax.java | 537 ++++ libjava/classpath/gnu/java/util/regex/REToken.java | 244 ++ .../classpath/gnu/java/util/regex/RETokenAny.java | 115 + .../gnu/java/util/regex/RETokenBackRef.java | 100 + .../classpath/gnu/java/util/regex/RETokenChar.java | 162 ++ .../classpath/gnu/java/util/regex/RETokenEnd.java | 151 ++ .../java/util/regex/RETokenEndOfPreviousMatch.java | 88 + .../gnu/java/util/regex/RETokenEndSub.java | 79 + .../gnu/java/util/regex/RETokenIndependent.java | 85 + .../gnu/java/util/regex/RETokenLookAhead.java | 88 + .../gnu/java/util/regex/RETokenLookBehind.java | 136 + .../gnu/java/util/regex/RETokenNamedProperty.java | 410 +++ .../gnu/java/util/regex/RETokenOneOf.java | 332 +++ .../gnu/java/util/regex/RETokenPOSIX.java | 195 ++ .../gnu/java/util/regex/RETokenRange.java | 119 + .../gnu/java/util/regex/RETokenRepeated.java | 639 +++++ .../gnu/java/util/regex/RETokenStart.java | 153 ++ .../gnu/java/util/regex/RETokenWordBoundary.java | 141 ++ .../classpath/gnu/java/util/regex/UncheckedRE.java | 114 + 807 files changed, 164849 insertions(+) create mode 100644 libjava/classpath/gnu/java/awt/AWTUtilities.java create mode 100644 libjava/classpath/gnu/java/awt/BitMaskExtent.java create mode 100644 libjava/classpath/gnu/java/awt/BitwiseXORComposite.java create mode 100644 libjava/classpath/gnu/java/awt/Buffers.java create mode 100644 libjava/classpath/gnu/java/awt/ClasspathGraphicsEnvironment.java create mode 100644 libjava/classpath/gnu/java/awt/ClasspathToolkit.java create mode 100644 libjava/classpath/gnu/java/awt/ComponentDataBlitOp.java create mode 100644 libjava/classpath/gnu/java/awt/ComponentReshapeEvent.java create mode 100644 libjava/classpath/gnu/java/awt/EmbeddedWindow.java create mode 100644 libjava/classpath/gnu/java/awt/EventModifier.java create mode 100644 libjava/classpath/gnu/java/awt/GradientPaintContext.java create mode 100644 libjava/classpath/gnu/java/awt/LowPriorityEvent.java create mode 100644 libjava/classpath/gnu/java/awt/color/CieXyzConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/ClutProfileConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/ColorLookUpTable.java create mode 100644 libjava/classpath/gnu/java/awt/color/ColorSpaceConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/GrayProfileConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/GrayScaleConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/LinearRGBConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/ProfileHeader.java create mode 100644 libjava/classpath/gnu/java/awt/color/PyccConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/RgbProfileConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/SrgbConverter.java create mode 100644 libjava/classpath/gnu/java/awt/color/TagEntry.java create mode 100644 libjava/classpath/gnu/java/awt/color/ToneReproductionCurve.java create mode 100644 libjava/classpath/gnu/java/awt/color/package.html create mode 100644 libjava/classpath/gnu/java/awt/dnd/GtkMouseDragGestureRecognizer.java create mode 100644 libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java create mode 100644 libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java create mode 100644 libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetPeer.java create mode 100644 libjava/classpath/gnu/java/awt/doc-files/BitwiseXORComposite-1.png create mode 100644 libjava/classpath/gnu/java/awt/font/FontDelegate.java create mode 100644 libjava/classpath/gnu/java/awt/font/FontFactory.java create mode 100644 libjava/classpath/gnu/java/awt/font/GNUGlyphVector.java create mode 100644 libjava/classpath/gnu/java/awt/font/OpenTypeFontPeer.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/AutoHinter.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/AxisHints.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/Constants.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/Edge.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/GlyphHints.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/HintScaler.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/Latin.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/LatinAxis.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/LatinBlue.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/LatinMetrics.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/Script.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/ScriptMetrics.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/Segment.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/Utils.java create mode 100644 libjava/classpath/gnu/java/awt/font/autofit/Width.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/CharGlyphMap.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/GlyphNamer.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/Hinter.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/MacResourceFork.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/NameDecoder.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFontFactory.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/Scaler.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/Fixed.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLocator.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphMeasurer.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/Point.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/VirtualMachine.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/Zone.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/ZonePathIterator.java create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/doc-files/ZonePathIterator-1.dia create mode 100644 libjava/classpath/gnu/java/awt/font/opentype/truetype/doc-files/ZonePathIterator-1.png create mode 100644 libjava/classpath/gnu/java/awt/image/AsyncImage.java create mode 100644 libjava/classpath/gnu/java/awt/image/ImageConverter.java create mode 100644 libjava/classpath/gnu/java/awt/image/ImageDecoder.java create mode 100644 libjava/classpath/gnu/java/awt/image/XBMDecoder.java create mode 100644 libjava/classpath/gnu/java/awt/image/package.html create mode 100644 libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/ActiveEdges.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/AlphaCompositeContext.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/CubicSegment.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/ImagePaint.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/LineSegment.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/PixelCoverage.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/Pixelizer.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/PolyEdge.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/PolyEdgeComparator.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/QuadSegment.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/RasterGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/Scanline.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/ScanlineConverter.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/ScanlineCoverage.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/Segment.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/ShapeCache.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/ShapeWrapper.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/TextCacheKey.java create mode 100644 libjava/classpath/gnu/java/awt/java2d/TexturePaintContext.java create mode 100644 libjava/classpath/gnu/java/awt/package.html create mode 100644 libjava/classpath/gnu/java/awt/peer/ClasspathDesktopPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/EmbeddedWindowPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/GnomeDesktopPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/KDEDesktopPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/NativeEventLoopRunningEvent.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphicsCopy.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GdkRobotPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkButtonPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkCanvasPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxMenuItemPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkCheckboxPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkCursor.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkDialogPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkEmbeddedWindowPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkGenericPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkPanelPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/gtk/package.html create mode 100644 libjava/classpath/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java create mode 100644 libjava/classpath/gnu/java/awt/peer/headless/HeadlessToolkit.java create mode 100644 libjava/classpath/gnu/java/awt/peer/package.html create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/MainQtThread.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/NativeWrapper.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QMatrix.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QPainterPath.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QPen.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtAudioClip.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtButtonPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtCanvasPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtCheckboxPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtChoicePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtComponentGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtComponentPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtContainerPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtDialogPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtEmbeddedWindowPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtFileDialogPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtFontMetrics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtFontPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtFramePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtGraphicsEnvironment.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtImage.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtImageConsumer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtImageDirectGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtImageGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtLabelPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtListPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtMenuBarPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtMenuComponentPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtMenuItemPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtMenuPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtPanelPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtPopupMenuPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtRepaintThread.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtScreenDevice.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtScreenDeviceConfiguration.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtScrollPanePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtScrollbarPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtTextAreaPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtTextFieldPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtToolkit.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtVolatileImage.java create mode 100644 libjava/classpath/gnu/java/awt/peer/qt/QtWindowPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingButtonPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingCanvasPeer.java create mode 100755 libjava/classpath/gnu/java/awt/peer/swing/SwingCheckboxPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingLabelPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingListPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingMenuItemPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingMenuPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingPanelPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingTextAreaPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingToolkit.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/swing/package.html create mode 100644 libjava/classpath/gnu/java/awt/peer/x/GLGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/KeyboardMapping.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/PixmapVolatileImage.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XDialogPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XEventPump.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XFontPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XFramePeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XGraphics2D.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XGraphicsConfiguration.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XGraphicsDevice.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XGraphicsEnvironment.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XImage.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XToolkit.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/XWindowPeer.java create mode 100644 libjava/classpath/gnu/java/awt/peer/x/ZPixmapDataBuffer.java create mode 100644 libjava/classpath/gnu/java/awt/print/JavaPrinterGraphics.java create mode 100644 libjava/classpath/gnu/java/awt/print/JavaPrinterJob.java create mode 100644 libjava/classpath/gnu/java/awt/print/PostScriptGraphics2D.java create mode 100644 libjava/classpath/gnu/java/awt/print/SpooledDocument.java create mode 100644 libjava/classpath/gnu/java/beans/BeanInfoEmbryo.java create mode 100644 libjava/classpath/gnu/java/beans/DefaultExceptionListener.java create mode 100644 libjava/classpath/gnu/java/beans/DummyAppletContext.java create mode 100644 libjava/classpath/gnu/java/beans/DummyAppletStub.java create mode 100644 libjava/classpath/gnu/java/beans/ExplicitBeanInfo.java create mode 100644 libjava/classpath/gnu/java/beans/IntrospectionIncubator.java create mode 100644 libjava/classpath/gnu/java/beans/TODO create mode 100644 libjava/classpath/gnu/java/beans/decoder/AbstractContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/AbstractCreatableObjectContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/AbstractElementHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/AbstractObjectContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ArrayContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ArrayHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/AssemblyException.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/BooleanHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ByteHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/CharHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ClassHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ConstructorContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/Context.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/DecoderContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/DoubleHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/DummyContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/DummyHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ElementHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/FloatHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/GrowableArrayContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/IndexContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/IntHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/JavaHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/LongHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/MethodContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/MethodFinder.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/NullHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ObjectContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ObjectHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/PersistenceParser.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/PropertyContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/ShortHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/SimpleHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/StaticMethodContext.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/StringHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/VoidHandler.java create mode 100644 libjava/classpath/gnu/java/beans/decoder/package.html create mode 100644 libjava/classpath/gnu/java/beans/editors/ColorEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/FontEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/NativeBooleanEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/NativeByteEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/NativeDoubleEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/NativeFloatEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/NativeIntEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/NativeLongEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/NativeShortEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/StringEditor.java create mode 100644 libjava/classpath/gnu/java/beans/editors/TODO create mode 100644 libjava/classpath/gnu/java/beans/editors/package.html create mode 100644 libjava/classpath/gnu/java/beans/encoder/ArrayPersistenceDelegate.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/ClassPersistenceDelegate.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/CollectionPersistenceDelegate.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/Context.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/GenericScannerState.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/IgnoringScannerState.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/MapPersistenceDelegate.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/ObjectId.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/PrimitivePersistenceDelegate.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/ReportingScannerState.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/Root.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/ScanEngine.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/ScannerState.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/StAXWriter.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/Writer.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/ArrayInstantiation.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/Array_Get.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/Array_Set.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/ClassResolution.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/Element.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/List_Get.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/List_Set.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/MethodInvocation.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/NullObject.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/ObjectInstantiation.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/ObjectReference.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/PrimitiveInstantiation.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/StaticFieldAccess.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/StaticMethodInvocation.java create mode 100644 libjava/classpath/gnu/java/beans/encoder/elements/StringReference.java create mode 100644 libjava/classpath/gnu/java/beans/package.html create mode 100644 libjava/classpath/gnu/java/io/ASN1ParsingException.java create mode 100644 libjava/classpath/gnu/java/io/Base64InputStream.java create mode 100644 libjava/classpath/gnu/java/io/ClassLoaderObjectInputStream.java create mode 100644 libjava/classpath/gnu/java/io/NullOutputStream.java create mode 100644 libjava/classpath/gnu/java/io/ObjectIdentityMap2Int.java create mode 100644 libjava/classpath/gnu/java/io/ObjectIdentityWrapper.java create mode 100644 libjava/classpath/gnu/java/io/PlatformHelper.java create mode 100644 libjava/classpath/gnu/java/io/package.html create mode 100644 libjava/classpath/gnu/java/lang/ArrayHelper.java create mode 100644 libjava/classpath/gnu/java/lang/CPStringBuilder.java create mode 100644 libjava/classpath/gnu/java/lang/CharData.java create mode 100644 libjava/classpath/gnu/java/lang/ClassHelper.java create mode 100644 libjava/classpath/gnu/java/lang/InstrumentationImpl.java create mode 100644 libjava/classpath/gnu/java/lang/MainThread.java create mode 100644 libjava/classpath/gnu/java/lang/management/BeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/ClassLoadingMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/CompilationMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/GarbageCollectorMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/MemoryMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/MemoryManagerMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/MemoryPoolMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/OperatingSystemMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/RuntimeMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/ThreadMXBeanImpl.java create mode 100644 libjava/classpath/gnu/java/lang/management/package.html create mode 100644 libjava/classpath/gnu/java/lang/package.html create mode 100644 libjava/classpath/gnu/java/lang/reflect/ClassSignatureParser.java create mode 100644 libjava/classpath/gnu/java/lang/reflect/FieldSignatureParser.java create mode 100644 libjava/classpath/gnu/java/lang/reflect/GenericSignatureParser.java create mode 100644 libjava/classpath/gnu/java/lang/reflect/MethodSignatureParser.java create mode 100644 libjava/classpath/gnu/java/lang/reflect/TypeImpl.java create mode 100644 libjava/classpath/gnu/java/lang/reflect/TypeSignature.java create mode 100644 libjava/classpath/gnu/java/lang/reflect/package.html create mode 100644 libjava/classpath/gnu/java/locale/.cvsignore create mode 100644 libjava/classpath/gnu/java/locale/LocaleHelper.java create mode 100644 libjava/classpath/gnu/java/locale/package.html create mode 100644 libjava/classpath/gnu/java/math/Fixed.java create mode 100644 libjava/classpath/gnu/java/math/GMP.java create mode 100644 libjava/classpath/gnu/java/math/MPN.java create mode 100644 libjava/classpath/gnu/java/math/package.html create mode 100644 libjava/classpath/gnu/java/net/CRLFInputStream.java create mode 100644 libjava/classpath/gnu/java/net/CRLFOutputStream.java create mode 100644 libjava/classpath/gnu/java/net/DefaultContentHandlerFactory.java create mode 100644 libjava/classpath/gnu/java/net/DefaultProxySelector.java create mode 100644 libjava/classpath/gnu/java/net/EmptyX509TrustManager.java create mode 100644 libjava/classpath/gnu/java/net/GetLocalHostAction.java create mode 100644 libjava/classpath/gnu/java/net/HeaderFieldHelper.java create mode 100644 libjava/classpath/gnu/java/net/IndexListParser.java create mode 100644 libjava/classpath/gnu/java/net/LineInputStream.java create mode 100644 libjava/classpath/gnu/java/net/PlainDatagramSocketImpl.java create mode 100644 libjava/classpath/gnu/java/net/PlainSocketImpl.java create mode 100644 libjava/classpath/gnu/java/net/URLParseError.java create mode 100644 libjava/classpath/gnu/java/net/loader/FileResource.java create mode 100644 libjava/classpath/gnu/java/net/loader/FileURLLoader.java create mode 100644 libjava/classpath/gnu/java/net/loader/JarURLLoader.java create mode 100644 libjava/classpath/gnu/java/net/loader/JarURLResource.java create mode 100644 libjava/classpath/gnu/java/net/loader/RemoteResource.java create mode 100644 libjava/classpath/gnu/java/net/loader/RemoteURLLoader.java create mode 100644 libjava/classpath/gnu/java/net/loader/Resource.java create mode 100644 libjava/classpath/gnu/java/net/loader/URLLoader.java create mode 100644 libjava/classpath/gnu/java/net/loader/URLStreamHandlerCache.java create mode 100644 libjava/classpath/gnu/java/net/local/LocalServerSocket.java create mode 100644 libjava/classpath/gnu/java/net/local/LocalSocket.java create mode 100644 libjava/classpath/gnu/java/net/local/LocalSocketAddress.java create mode 100644 libjava/classpath/gnu/java/net/local/LocalSocketImpl.java create mode 100644 libjava/classpath/gnu/java/net/package.html create mode 100644 libjava/classpath/gnu/java/net/protocol/file/Connection.java create mode 100644 libjava/classpath/gnu/java/net/protocol/file/Handler.java create mode 100644 libjava/classpath/gnu/java/net/protocol/file/package.html create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/ActiveModeDTP.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/BlockInputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/BlockOutputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/CompressedInputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/CompressedOutputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/DTP.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/DTPInputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/DTPOutputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/FTPConnection.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/FTPException.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/FTPResponse.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/FTPURLConnection.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/Handler.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/PassiveModeDTP.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/StreamInputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/StreamOutputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/ftp/package.html create mode 100644 libjava/classpath/gnu/java/net/protocol/http/Authenticator.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/ByteArrayRequestBodyWriter.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/ChunkedInputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/Cookie.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/CookieManager.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/Credentials.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/HTTPConnection.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/HTTPDateFormat.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/HTTPURLConnection.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/Handler.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/Headers.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/LimitedLengthInputStream.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/Request.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/RequestBodyWriter.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/Response.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/ResponseHeaderHandler.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/SimpleCookieManager.java create mode 100644 libjava/classpath/gnu/java/net/protocol/http/package.html create mode 100644 libjava/classpath/gnu/java/net/protocol/https/Handler.java create mode 100644 libjava/classpath/gnu/java/net/protocol/jar/Connection.java create mode 100644 libjava/classpath/gnu/java/net/protocol/jar/Handler.java create mode 100644 libjava/classpath/gnu/java/net/protocol/jar/package.html create mode 100644 libjava/classpath/gnu/java/nio/ChannelInputStream.java create mode 100644 libjava/classpath/gnu/java/nio/ChannelOutputStream.java create mode 100644 libjava/classpath/gnu/java/nio/ChannelReader.java create mode 100644 libjava/classpath/gnu/java/nio/ChannelWriter.java create mode 100644 libjava/classpath/gnu/java/nio/DatagramChannelImpl.java create mode 100644 libjava/classpath/gnu/java/nio/DatagramChannelSelectionKey.java create mode 100644 libjava/classpath/gnu/java/nio/EpollSelectionKeyImpl.java create mode 100644 libjava/classpath/gnu/java/nio/EpollSelectorImpl.java create mode 100644 libjava/classpath/gnu/java/nio/FileChannelImpl.java create mode 100644 libjava/classpath/gnu/java/nio/FileLockImpl.java create mode 100644 libjava/classpath/gnu/java/nio/InputStreamChannel.java create mode 100644 libjava/classpath/gnu/java/nio/KqueueSelectionKeyImpl.java create mode 100644 libjava/classpath/gnu/java/nio/KqueueSelectorImpl.java create mode 100644 libjava/classpath/gnu/java/nio/NIOConstants.java create mode 100644 libjava/classpath/gnu/java/nio/NIODatagramSocket.java create mode 100644 libjava/classpath/gnu/java/nio/NIOServerSocket.java create mode 100644 libjava/classpath/gnu/java/nio/NIOSocket.java create mode 100644 libjava/classpath/gnu/java/nio/NIOSocketImpl.java create mode 100644 libjava/classpath/gnu/java/nio/OutputStreamChannel.java create mode 100644 libjava/classpath/gnu/java/nio/PipeImpl.java create mode 100644 libjava/classpath/gnu/java/nio/SelectionKeyImpl.java create mode 100644 libjava/classpath/gnu/java/nio/SelectorImpl.java create mode 100644 libjava/classpath/gnu/java/nio/SelectorProviderImpl.java create mode 100644 libjava/classpath/gnu/java/nio/ServerSocketChannelImpl.java create mode 100644 libjava/classpath/gnu/java/nio/ServerSocketChannelSelectionKey.java create mode 100644 libjava/classpath/gnu/java/nio/SocketChannelImpl.java create mode 100644 libjava/classpath/gnu/java/nio/SocketChannelSelectionKey.java create mode 100644 libjava/classpath/gnu/java/nio/SocketChannelSelectionKeyImpl.java create mode 100644 libjava/classpath/gnu/java/nio/VMChannelOwner.java create mode 100644 libjava/classpath/gnu/java/nio/channels/package.html create mode 100644 libjava/classpath/gnu/java/nio/charset/ByteCharset.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ByteDecodeLoopHelper.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ByteEncodeLoopHelper.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp424.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp437.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp737.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp775.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp850.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp852.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp855.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp857.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp860.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp861.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp862.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp863.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp864.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp865.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp866.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp869.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Cp874.java create mode 100644 libjava/classpath/gnu/java/nio/charset/EncodingHelper.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_1.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_13.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_15.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_2.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_3.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_4.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_5.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_6.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_7.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_8.java create mode 100644 libjava/classpath/gnu/java/nio/charset/ISO_8859_9.java create mode 100644 libjava/classpath/gnu/java/nio/charset/KOI_8.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MS874.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacCentralEurope.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacCroatian.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacCyrillic.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacDingbat.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacGreek.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacIceland.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacRoman.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacRomania.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacSymbol.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacThai.java create mode 100644 libjava/classpath/gnu/java/nio/charset/MacTurkish.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Provider.java create mode 100644 libjava/classpath/gnu/java/nio/charset/US_ASCII.java create mode 100644 libjava/classpath/gnu/java/nio/charset/UTF_16.java create mode 100644 libjava/classpath/gnu/java/nio/charset/UTF_16BE.java create mode 100644 libjava/classpath/gnu/java/nio/charset/UTF_16Decoder.java create mode 100644 libjava/classpath/gnu/java/nio/charset/UTF_16Encoder.java create mode 100644 libjava/classpath/gnu/java/nio/charset/UTF_16LE.java create mode 100644 libjava/classpath/gnu/java/nio/charset/UTF_8.java create mode 100644 libjava/classpath/gnu/java/nio/charset/UnicodeLittle.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1250.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1251.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1252.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1253.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1254.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1255.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1256.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1257.java create mode 100644 libjava/classpath/gnu/java/nio/charset/Windows1258.java create mode 100644 libjava/classpath/gnu/java/nio/charset/iconv/IconvCharset.java create mode 100644 libjava/classpath/gnu/java/nio/charset/iconv/IconvDecoder.java create mode 100644 libjava/classpath/gnu/java/nio/charset/iconv/IconvEncoder.java create mode 100644 libjava/classpath/gnu/java/nio/charset/iconv/IconvMetaData.java create mode 100644 libjava/classpath/gnu/java/nio/charset/iconv/IconvProvider.java create mode 100644 libjava/classpath/gnu/java/nio/charset/package.html create mode 100644 libjava/classpath/gnu/java/nio/package.html create mode 100644 libjava/classpath/gnu/java/rmi/RMIMarshalledObjectInputStream.java create mode 100644 libjava/classpath/gnu/java/rmi/RMIMarshalledObjectOutputStream.java create mode 100644 libjava/classpath/gnu/java/rmi/activation/ActivationSystemTransient.java create mode 100644 libjava/classpath/gnu/java/rmi/activation/BidiTable.java create mode 100644 libjava/classpath/gnu/java/rmi/activation/DefaultActivationGroup.java create mode 100644 libjava/classpath/gnu/java/rmi/activation/DefaultActivationSystem.java create mode 100644 libjava/classpath/gnu/java/rmi/dgc/DGCImpl.java create mode 100644 libjava/classpath/gnu/java/rmi/dgc/DGCImpl_Skel.java create mode 100644 libjava/classpath/gnu/java/rmi/dgc/DGCImpl_Stub.java create mode 100644 libjava/classpath/gnu/java/rmi/dgc/LeaseRenewingTask.java create mode 100644 libjava/classpath/gnu/java/rmi/dgc/package.html create mode 100644 libjava/classpath/gnu/java/rmi/package.html create mode 100644 libjava/classpath/gnu/java/rmi/registry/RegistryImpl.java create mode 100644 libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Skel.java create mode 100644 libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Stub.java create mode 100644 libjava/classpath/gnu/java/rmi/registry/package.html create mode 100644 libjava/classpath/gnu/java/rmi/server/ActivatableRef.java create mode 100644 libjava/classpath/gnu/java/rmi/server/ActivatableServerRef.java create mode 100644 libjava/classpath/gnu/java/rmi/server/CombinedClassLoader.java create mode 100644 libjava/classpath/gnu/java/rmi/server/ConnectionRunnerPool.java create mode 100644 libjava/classpath/gnu/java/rmi/server/ProtocolConstants.java create mode 100644 libjava/classpath/gnu/java/rmi/server/RMIClassLoaderImpl.java create mode 100644 libjava/classpath/gnu/java/rmi/server/RMIDefaultSocketFactory.java create mode 100644 libjava/classpath/gnu/java/rmi/server/RMIHashes.java create mode 100644 libjava/classpath/gnu/java/rmi/server/RMIIncomingThread.java create mode 100644 libjava/classpath/gnu/java/rmi/server/RMIObjectInputStream.java create mode 100644 libjava/classpath/gnu/java/rmi/server/RMIObjectOutputStream.java create mode 100644 libjava/classpath/gnu/java/rmi/server/RMIVoidValue.java create mode 100644 libjava/classpath/gnu/java/rmi/server/UnicastConnection.java create mode 100644 libjava/classpath/gnu/java/rmi/server/UnicastConnectionManager.java create mode 100644 libjava/classpath/gnu/java/rmi/server/UnicastRef.java create mode 100644 libjava/classpath/gnu/java/rmi/server/UnicastRemoteCall.java create mode 100644 libjava/classpath/gnu/java/rmi/server/UnicastRemoteStub.java create mode 100644 libjava/classpath/gnu/java/rmi/server/UnicastServer.java create mode 100644 libjava/classpath/gnu/java/rmi/server/UnicastServerRef.java create mode 100644 libjava/classpath/gnu/java/rmi/server/package.html create mode 100644 libjava/classpath/gnu/java/security/.cvsignore create mode 100644 libjava/classpath/gnu/java/security/Configuration.java.in create mode 100644 libjava/classpath/gnu/java/security/Engine.java create mode 100644 libjava/classpath/gnu/java/security/OID.java create mode 100644 libjava/classpath/gnu/java/security/PolicyFile.java create mode 100644 libjava/classpath/gnu/java/security/Properties.java create mode 100644 libjava/classpath/gnu/java/security/Registry.java create mode 100644 libjava/classpath/gnu/java/security/Requires.java create mode 100644 libjava/classpath/gnu/java/security/action/GetPropertyAction.java create mode 100644 libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java create mode 100644 libjava/classpath/gnu/java/security/action/SetAccessibleAction.java create mode 100644 libjava/classpath/gnu/java/security/action/package.html create mode 100644 libjava/classpath/gnu/java/security/ber/BER.java create mode 100644 libjava/classpath/gnu/java/security/ber/BEREncodingException.java create mode 100644 libjava/classpath/gnu/java/security/ber/BERReader.java create mode 100644 libjava/classpath/gnu/java/security/ber/BERValue.java create mode 100644 libjava/classpath/gnu/java/security/ber/package.html create mode 100644 libjava/classpath/gnu/java/security/der/BitString.java create mode 100644 libjava/classpath/gnu/java/security/der/DER.java create mode 100644 libjava/classpath/gnu/java/security/der/DEREncodingException.java create mode 100644 libjava/classpath/gnu/java/security/der/DERReader.java create mode 100644 libjava/classpath/gnu/java/security/der/DERValue.java create mode 100644 libjava/classpath/gnu/java/security/der/DERWriter.java create mode 100644 libjava/classpath/gnu/java/security/der/package.html create mode 100644 libjava/classpath/gnu/java/security/hash/BaseHash.java create mode 100644 libjava/classpath/gnu/java/security/hash/HashFactory.java create mode 100644 libjava/classpath/gnu/java/security/hash/Haval.java create mode 100644 libjava/classpath/gnu/java/security/hash/IMessageDigest.java create mode 100644 libjava/classpath/gnu/java/security/hash/MD2.java create mode 100644 libjava/classpath/gnu/java/security/hash/MD4.java create mode 100644 libjava/classpath/gnu/java/security/hash/MD5.java create mode 100644 libjava/classpath/gnu/java/security/hash/RipeMD128.java create mode 100644 libjava/classpath/gnu/java/security/hash/RipeMD160.java create mode 100644 libjava/classpath/gnu/java/security/hash/Sha160.java create mode 100644 libjava/classpath/gnu/java/security/hash/Sha256.java create mode 100644 libjava/classpath/gnu/java/security/hash/Sha384.java create mode 100644 libjava/classpath/gnu/java/security/hash/Sha512.java create mode 100644 libjava/classpath/gnu/java/security/hash/Tiger.java create mode 100644 libjava/classpath/gnu/java/security/hash/Whirlpool.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/HavalSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/MD2Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/MD4Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/MD5Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/MessageDigestAdapter.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/RipeMD128Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/RipeMD160Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/Sha160Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/Sha256Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/Sha384Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/Sha512Spi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/TigerSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/hash/WhirlpoolSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/HavalRandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/MD2RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/MD4RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/MD5RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/RipeMD128RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/RipeMD160RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/SecureRandomAdapter.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/Sha160RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/Sha256RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/Sha384RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/Sha512RandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/TigerRandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/DSSKeyFactory.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/DSSParameters.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/DSSParametersGenerator.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/DSSRawSignatureSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/EncodedKeyFactory.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/MD2withRSA.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/MD5withRSA.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/RSAKeyFactory.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/RSAKeyPairGeneratorSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/SHA160withDSS.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/SHA160withRSA.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/SHA256withRSA.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/SHA384withRSA.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/SHA512withRSA.java create mode 100644 libjava/classpath/gnu/java/security/jce/sig/SignatureAdapter.java create mode 100644 libjava/classpath/gnu/java/security/key/IKeyPairCodec.java create mode 100644 libjava/classpath/gnu/java/security/key/IKeyPairGenerator.java create mode 100644 libjava/classpath/gnu/java/security/key/KeyPairCodecFactory.java create mode 100644 libjava/classpath/gnu/java/security/key/KeyPairGeneratorFactory.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKey.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSKeyPairX509Codec.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java create mode 100644 libjava/classpath/gnu/java/security/key/dss/FIPS186.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/GnuRSAKey.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/GnuRSAPrivateKey.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/GnuRSAPublicKey.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairGenerator.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairX509Codec.java create mode 100644 libjava/classpath/gnu/java/security/package.html create mode 100644 libjava/classpath/gnu/java/security/pkcs/PKCS7Data.java create mode 100644 libjava/classpath/gnu/java/security/pkcs/PKCS7SignedData.java create mode 100644 libjava/classpath/gnu/java/security/pkcs/SignerInfo.java create mode 100644 libjava/classpath/gnu/java/security/pkcs/package.html create mode 100644 libjava/classpath/gnu/java/security/prng/BasePRNG.java create mode 100644 libjava/classpath/gnu/java/security/prng/EntropySource.java create mode 100644 libjava/classpath/gnu/java/security/prng/IRandom.java create mode 100644 libjava/classpath/gnu/java/security/prng/LimitReachedException.java create mode 100644 libjava/classpath/gnu/java/security/prng/MDGenerator.java create mode 100644 libjava/classpath/gnu/java/security/prng/PRNGFactory.java create mode 100644 libjava/classpath/gnu/java/security/prng/RandomEvent.java create mode 100644 libjava/classpath/gnu/java/security/prng/RandomEventListener.java create mode 100644 libjava/classpath/gnu/java/security/provider/CollectionCertStoreImpl.java create mode 100644 libjava/classpath/gnu/java/security/provider/DefaultPolicy.java create mode 100644 libjava/classpath/gnu/java/security/provider/Gnu.java create mode 100644 libjava/classpath/gnu/java/security/provider/PKIXCertPathValidatorImpl.java create mode 100644 libjava/classpath/gnu/java/security/provider/X509CertificateFactory.java create mode 100644 libjava/classpath/gnu/java/security/provider/package.html create mode 100644 libjava/classpath/gnu/java/security/sig/BaseSignature.java create mode 100644 libjava/classpath/gnu/java/security/sig/ISignature.java create mode 100644 libjava/classpath/gnu/java/security/sig/ISignatureCodec.java create mode 100644 libjava/classpath/gnu/java/security/sig/SignatureCodecFactory.java create mode 100644 libjava/classpath/gnu/java/security/sig/SignatureFactory.java create mode 100644 libjava/classpath/gnu/java/security/sig/dss/DSSSignature.java create mode 100644 libjava/classpath/gnu/java/security/sig/dss/DSSSignatureRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/sig/dss/DSSSignatureX509Codec.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/EME_PKCS1_V1_5.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/EMSA_PKCS1_V1_5.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSA.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5SignatureX509Codec.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java create mode 100644 libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java create mode 100644 libjava/classpath/gnu/java/security/util/ByteArray.java create mode 100644 libjava/classpath/gnu/java/security/util/ByteBufferOutputStream.java create mode 100644 libjava/classpath/gnu/java/security/util/DerUtil.java create mode 100644 libjava/classpath/gnu/java/security/util/ExpirableObject.java create mode 100644 libjava/classpath/gnu/java/security/util/FormatUtil.java create mode 100644 libjava/classpath/gnu/java/security/util/IntegerUtil.java create mode 100644 libjava/classpath/gnu/java/security/util/PRNG.java create mode 100644 libjava/classpath/gnu/java/security/util/Prime.java create mode 100644 libjava/classpath/gnu/java/security/util/Sequence.java create mode 100644 libjava/classpath/gnu/java/security/util/SimpleList.java create mode 100644 libjava/classpath/gnu/java/security/util/Util.java create mode 100644 libjava/classpath/gnu/java/security/util/package.html create mode 100644 libjava/classpath/gnu/java/security/x509/GnuPKIExtension.java create mode 100644 libjava/classpath/gnu/java/security/x509/PolicyNodeImpl.java create mode 100644 libjava/classpath/gnu/java/security/x509/Util.java create mode 100644 libjava/classpath/gnu/java/security/x509/X500DistinguishedName.java create mode 100644 libjava/classpath/gnu/java/security/x509/X509CRL.java create mode 100644 libjava/classpath/gnu/java/security/x509/X509CRLEntry.java create mode 100644 libjava/classpath/gnu/java/security/x509/X509CRLSelectorImpl.java create mode 100644 libjava/classpath/gnu/java/security/x509/X509CertPath.java create mode 100644 libjava/classpath/gnu/java/security/x509/X509CertSelectorImpl.java create mode 100644 libjava/classpath/gnu/java/security/x509/X509Certificate.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/AuthorityKeyIdentifier.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/BasicConstraints.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/CRLNumber.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/CertificatePolicies.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/ExtendedKeyUsage.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/Extension.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/GeneralName.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/GeneralNames.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/GeneralSubtree.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/IssuerAlternativeNames.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/KeyUsage.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/NameConstraints.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/PolicyConstraint.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/PolicyMappings.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/PrivateKeyUsagePeriod.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/ReasonCode.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/SubjectAlternativeNames.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/SubjectKeyIdentifier.java create mode 100644 libjava/classpath/gnu/java/security/x509/ext/package.html create mode 100644 libjava/classpath/gnu/java/security/x509/package.html create mode 100644 libjava/classpath/gnu/java/text/AttributedFormatBuffer.java create mode 100644 libjava/classpath/gnu/java/text/BaseBreakIterator.java create mode 100644 libjava/classpath/gnu/java/text/CharacterBreakIterator.java create mode 100644 libjava/classpath/gnu/java/text/FormatBuffer.java create mode 100644 libjava/classpath/gnu/java/text/FormatCharacterIterator.java create mode 100644 libjava/classpath/gnu/java/text/LineBreakIterator.java create mode 100644 libjava/classpath/gnu/java/text/SentenceBreakIterator.java create mode 100644 libjava/classpath/gnu/java/text/StringFormatBuffer.java create mode 100644 libjava/classpath/gnu/java/text/WordBreakIterator.java create mode 100644 libjava/classpath/gnu/java/text/package.html create mode 100644 libjava/classpath/gnu/java/util/Base64.java create mode 100644 libjava/classpath/gnu/java/util/DoubleEnumeration.java create mode 100644 libjava/classpath/gnu/java/util/EmptyEnumeration.java create mode 100644 libjava/classpath/gnu/java/util/LRUCache.java create mode 100644 libjava/classpath/gnu/java/util/WeakIdentityHashMap.java create mode 100644 libjava/classpath/gnu/java/util/ZoneInfo.java create mode 100644 libjava/classpath/gnu/java/util/jar/JarUtils.java create mode 100644 libjava/classpath/gnu/java/util/package.html create mode 100644 libjava/classpath/gnu/java/util/prefs/FileBasedFactory.java create mode 100644 libjava/classpath/gnu/java/util/prefs/FileBasedPreferences.java create mode 100644 libjava/classpath/gnu/java/util/prefs/GConfBasedFactory.java create mode 100644 libjava/classpath/gnu/java/util/prefs/GConfBasedPreferences.java create mode 100644 libjava/classpath/gnu/java/util/prefs/MemoryBasedFactory.java create mode 100644 libjava/classpath/gnu/java/util/prefs/MemoryBasedPreferences.java create mode 100644 libjava/classpath/gnu/java/util/prefs/NodeReader.java create mode 100644 libjava/classpath/gnu/java/util/prefs/NodeWriter.java create mode 100644 libjava/classpath/gnu/java/util/prefs/gconf/GConfNativePeer.java create mode 100644 libjava/classpath/gnu/java/util/prefs/package.html create mode 100644 libjava/classpath/gnu/java/util/regex/BacktrackStack.java create mode 100644 libjava/classpath/gnu/java/util/regex/CharIndexed.java create mode 100644 libjava/classpath/gnu/java/util/regex/CharIndexedCharArray.java create mode 100644 libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java create mode 100644 libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java create mode 100644 libjava/classpath/gnu/java/util/regex/CharIndexedString.java create mode 100644 libjava/classpath/gnu/java/util/regex/CharIndexedStringBuffer.java create mode 100644 libjava/classpath/gnu/java/util/regex/RE.java create mode 100644 libjava/classpath/gnu/java/util/regex/REException.java create mode 100644 libjava/classpath/gnu/java/util/regex/REFilterInputStream.java create mode 100644 libjava/classpath/gnu/java/util/regex/REMatch.java create mode 100644 libjava/classpath/gnu/java/util/regex/REMatchEnumeration.java create mode 100644 libjava/classpath/gnu/java/util/regex/RESyntax.java create mode 100644 libjava/classpath/gnu/java/util/regex/REToken.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenAny.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenBackRef.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenChar.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenEnd.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenEndOfPreviousMatch.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenEndSub.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenIndependent.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenLookAhead.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenLookBehind.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenNamedProperty.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenOneOf.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenPOSIX.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenRange.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenRepeated.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenStart.java create mode 100644 libjava/classpath/gnu/java/util/regex/RETokenWordBoundary.java create mode 100644 libjava/classpath/gnu/java/util/regex/UncheckedRE.java (limited to 'libjava/classpath/gnu/java') diff --git a/libjava/classpath/gnu/java/awt/AWTUtilities.java b/libjava/classpath/gnu/java/awt/AWTUtilities.java new file mode 100644 index 000000000..1b308cef4 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/AWTUtilities.java @@ -0,0 +1,898 @@ +/* AWTUtilities.java -- Common utility methods for AWT and Swing. + Copyright (C) 2005, 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt; + +import java.applet.Applet; +import java.awt.Component; +import java.awt.Container; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.util.AbstractSequentialList; +import java.util.List; +import java.util.ListIterator; +import java.util.NoSuchElementException; +import java.util.WeakHashMap; +import java.lang.reflect.InvocationTargetException; + +/** + * This class mirrors the javax.swing.SwingUtilities class. It + * provides commonly needed functionalities for AWT classes without + * the need to reference classes in the javax.swing package. + */ +public class AWTUtilities +{ + + /** + * This List implementation wraps the Component[] returned by + * {@link Container#getComponents()} and iterates over the visible Components + * in that array. This class is used in {@link #getVisibleChildren}. + */ + static class VisibleComponentList extends AbstractSequentialList + { + /** + * The ListIterator for this List. + */ + class VisibleComponentIterator implements ListIterator + { + /** The current index in the Component[]. */ + int index; + + /** The index in the List of visible Components. */ + int listIndex; + + /** + * Creates a new VisibleComponentIterator that starts at the specified + * listIndex. The array of Components is searched from + * the beginning to find the matching array index. + * + * @param listIndex the index from where to begin iterating + */ + VisibleComponentIterator(int listIndex) + { + this.listIndex = listIndex; + int visibleComponentsFound = 0; + for (index = 0; visibleComponentsFound != listIndex; index++) + { + if (components[index].isVisible()) + visibleComponentsFound++; + } + } + + /** + * Returns true if there are more visible components in the + * array, false otherwise. + * + * @return true if there are more visible components in the + * array, false otherwise + */ + public boolean hasNext() + { + boolean hasNext = false; + for (int i = index; i < components.length; i++) + { + if (components[i].isVisible()) + { + hasNext = true; + break; + } + } + return hasNext; + } + + /** + * Returns the next visible Component in the List. + * + * @return the next visible Component in the List + * + * @throws NoSuchElementException if there is no next element + */ + public Object next() + { + Object o = null; + for (; index < components.length; index++) + { + if (components[index].isVisible()) + { + o = components[index]; + break; + } + } + if (o != null) + { + index++; + listIndex++; + return o; + } + else + throw new NoSuchElementException(); + } + + /** + * Returns true if there are more visible components in the + * array in the reverse direction, false otherwise. + * + * @return true if there are more visible components in the + * array in the reverse direction, false otherwise + */ + public boolean hasPrevious() + { + boolean hasPrevious = false; + for (int i = index - 1; i >= 0; i--) + { + if (components[i].isVisible()) + { + hasPrevious = true; + break; + } + } + return hasPrevious; + } + + /** + * Returns the previous visible Component in the List. + * + * @return the previous visible Component in the List + * + * @throws NoSuchElementException if there is no previous element + */ + public Object previous() + { + Object o = null; + for (index--; index >= 0; index--) + { + if (components[index].isVisible()) + { + o = components[index]; + break; + } + } + if (o != null) + { + listIndex--; + return o; + } + else + throw new NoSuchElementException(); + } + + /** + * Returns the index of the next element in the List. + * + * @return the index of the next element in the List + */ + public int nextIndex() + { + return listIndex + 1; + } + + /** + * Returns the index of the previous element in the List. + * + * @return the index of the previous element in the List + */ + public int previousIndex() + { + return listIndex - 1; + } + + /** + * This operation is not supported because the List is immutable. + * + * @throws UnsupportedOperationException because the List is immutable + */ + public void remove() + { + throw new UnsupportedOperationException + ("VisibleComponentList is immutable"); + } + + /** + * This operation is not supported because the List is immutable. + * + * @param o not used here + * + * @throws UnsupportedOperationException because the List is immutable + */ + public void set(Object o) + { + throw new UnsupportedOperationException + ("VisibleComponentList is immutable"); + } + + /** + * This operation is not supported because the List is immutable. + * + * @param o not used here + * + * @throws UnsupportedOperationException because the List is immutable + */ + public void add(Object o) + { + throw new UnsupportedOperationException + ("VisibleComponentList is immutable"); + } + } + + /** + * The components over which we iterate. Only the visible components + * are returned by this List. + */ + Component[] components; + + /** + * Creates a new instance of VisibleComponentList that wraps the specified + * Component[]. + * + * @param c the Component[] to be wrapped. + */ + VisibleComponentList(Component[] c) + { + components = c; + } + + /** + * Returns a {@link ListIterator} for iterating over this List. + * + * @return a {@link ListIterator} for iterating over this List + */ + public ListIterator listIterator(int index) + { + return new VisibleComponentIterator(index); + } + + /** + * Returns the number of visible components in the wrapped Component[]. + * + * @return the number of visible components + */ + public int size() + { + int visibleComponents = 0; + for (int i = 0; i < components.length; i++) + if (components[i].isVisible()) + visibleComponents++; + return visibleComponents; + } + } + + /** + * The cache for our List instances. We try to hold one instance of + * VisibleComponentList for each Component[] that is requested. Note + * that we use a WeakHashMap for caching, so that the cache itself + * does not keep the array or the List from beeing garbage collected + * if no other objects hold references to it. + */ + static WeakHashMap visibleChildrenCache = new WeakHashMap(); + + /** + * Returns the visible children of a {@link Container}. This method is + * commonly needed in LayoutManagers, because they only have to layout + * the visible children of a Container. + * + * @param c the Container from which to extract the visible children + * + * @return the visible children of c + */ + public static List getVisibleChildren(Container c) + { + Component[] children = c.getComponents(); + Object o = visibleChildrenCache.get(children); + VisibleComponentList visibleChildren = null; + if (o == null) + { + visibleChildren = new VisibleComponentList(children); + visibleChildrenCache.put(children, visibleChildren); + } + else + visibleChildren = (VisibleComponentList) o; + + return visibleChildren; + } + + /** + * Calculates the portion of the base rectangle which is inside the + * insets. + * + * @param base The rectangle to apply the insets to + * @param insets The insets to apply to the base rectangle + * @param ret A rectangle to use for storing the return value, or + * null + * + * @return The calculated area inside the base rectangle and its insets, + * either stored in ret or a new Rectangle if ret is null + * + * @see #calculateInnerArea + */ + public static Rectangle calculateInsetArea(Rectangle base, Insets insets, + Rectangle ret) + { + if (ret == null) + ret = new Rectangle(); + ret.setBounds(base.x + insets.left, base.y + insets.top, + base.width - (insets.left + insets.right), + base.height - (insets.top + insets.bottom)); + return ret; + } + + /** + * Calculates the bounds of a component in the component's own coordinate + * space. The result has the same height and width as the component's + * bounds, but its location is set to (0,0). + * + * @param aComponent The component to measure + * + * @return The component's bounds in its local coordinate space + */ + public static Rectangle getLocalBounds(Component aComponent) + { + Rectangle bounds = aComponent.getBounds(); + return new Rectangle(0, 0, bounds.width, bounds.height); + } + + /** + * Returns the font metrics object for a given font. The metrics can be + * used to calculate crude bounding boxes and positioning information, + * for laying out components with textual elements. + * + * @param font The font to get metrics for + * + * @return The font's metrics + * + * @see java.awt.font.GlyphMetrics + */ + public static FontMetrics getFontMetrics(Font font) + { + return Toolkit.getDefaultToolkit().getFontMetrics(font); + } + + /** + * Returns the least ancestor of comp which has the + * specified name. + * + * @param name The name to search for + * @param comp The component to search the ancestors of + * + * @return The nearest ancestor of comp with the given + * name, or null if no such ancestor exists + * + * @see java.awt.Component#getName + * @see #getAncestorOfClass + */ + public static Container getAncestorNamed(String name, Component comp) + { + while (comp != null && (comp.getName() != name)) + comp = comp.getParent(); + return (Container) comp; + } + + /** + * Returns the least ancestor of comp which is an instance + * of the specified class. + * + * @param c The class to search for + * @param comp The component to search the ancestors of + * + * @return The nearest ancestor of comp which is an instance + * of the given class, or null if no such ancestor exists + * + * @see #getAncestorOfClass + * @see #windowForComponent + * @see + * + */ + public static Container getAncestorOfClass(Class c, Component comp) + { + while (comp != null && (! c.isInstance(comp))) + comp = comp.getParent(); + return (Container) comp; + } + + /** + * Equivalent to calling getAncestorOfClass(Window, comp). + * + * @param comp The component to search for an ancestor window + * + * @return An ancestral window, or null if none exists + */ + public static Window windowForComponent(Component comp) + { + return (Window) getAncestorOfClass(Window.class, comp); + } + + /** + * Returns the "root" of the component tree containint comp + * The root is defined as either the least ancestor of + * comp which is a {@link Window}, or the greatest + * ancestor of comp which is a {@link Applet} if no {@link + * Window} ancestors are found. + * + * @param comp The component to search for a root + * + * @return The root of the component's tree, or null + */ + public static Component getRoot(Component comp) + { + Applet app = null; + Window win = null; + + while (comp != null) + { + if (win == null && comp instanceof Window) + win = (Window) comp; + else if (comp instanceof Applet) + app = (Applet) comp; + comp = comp.getParent(); + } + + if (win != null) + return win; + else + return app; + } + + /** + * Return true if a descends from b, in other words if b is an + * ancestor of a. + * + * @param a The child to search the ancestry of + * @param b The potential ancestor to search for + * + * @return true if a is a descendent of b, false otherwise + */ + public static boolean isDescendingFrom(Component a, Component b) + { + while (true) + { + if (a == null || b == null) + return false; + if (a == b) + return true; + a = a.getParent(); + } + } + + /** + * Returns the deepest descendent of parent which is both visible and + * contains the point (x,y). Returns parent when either + * parent is not a container, or has no children which contain + * (x,y). Returns null when either + * (x,y) is outside the bounds of parent, or parent is + * null. + * + * @param parent The component to search the descendents of + * @param x Horizontal coordinate to search for + * @param y Vertical coordinate to search for + * + * @return A component containing (x,y), or + * null + * + * @see java.awt.Container#findComponentAt + */ + public static Component getDeepestComponentAt(Component parent, int x, int y) + { + if (parent == null || (! parent.contains(x, y))) + return null; + + if (! (parent instanceof Container)) + return parent; + + Container c = (Container) parent; + return c.findComponentAt(x, y); + } + + /** + * Converts a point from a component's local coordinate space to "screen" + * coordinates (such as the coordinate space mouse events are delivered + * in). This operation is equivalent to translating the point by the + * location of the component (which is the origin of its coordinate + * space). + * + * @param p The point to convert + * @param c The component which the point is expressed in terms of + * + * @see convertPointFromScreen + */ + public static void convertPointToScreen(Point p, Component c) + { + Point c0 = c.getLocationOnScreen(); + p.translate(c0.x, c0.y); + } + + /** + * Converts a point from "screen" coordinates (such as the coordinate + * space mouse events are delivered in) to a component's local coordinate + * space. This operation is equivalent to translating the point by the + * negation of the component's location (which is the origin of its + * coordinate space). + * + * @param p The point to convert + * @param c The component which the point should be expressed in terms of + */ + public static void convertPointFromScreen(Point p, Component c) + { + Point c0 = c.getLocationOnScreen(); + p.translate(-c0.x, -c0.y); + } + + /** + * Converts a point (x,y) from the coordinate space of one + * component to another. This is equivalent to converting the point from + * source space to screen space, then back from screen space + * to destination space. If exactly one of the two + * Components is null, it is taken to refer to the root + * ancestor of the other component. If both are null, no + * transformation is done. + * + * @param source The component which the point is expressed in terms of + * @param x Horizontal coordinate of point to transform + * @param y Vertical coordinate of point to transform + * @param destination The component which the return value will be + * expressed in terms of + * + * @return The point (x,y) converted from the coordinate + * space of the + * source component to the coordinate space of the destination component + * + * @see #convertPointToScreen + * @see #convertPointFromScreen + * @see #convertRectangle + * @see #getRoot + */ + public static Point convertPoint(Component source, int x, int y, + Component destination) + { + Point pt = new Point(x, y); + + if (source == null && destination == null) + return pt; + + if (source == null) + source = getRoot(destination); + + if (destination == null) + destination = getRoot(source); + + if (source.isShowing() && destination.isShowing()) + { + convertPointToScreen(pt, source); + convertPointFromScreen(pt, destination); + } + + return pt; + } + + + /** + * Converts a rectangle from the coordinate space of one component to + * another. This is equivalent to converting the rectangle from + * source space to screen space, then back from screen space + * to destination space. If exactly one of the two + * Components is null, it is taken to refer to the root + * ancestor of the other component. If both are null, no + * transformation is done. + * + * @param source The component which the rectangle is expressed in terms of + * @param rect The rectangle to convert + * @param destination The component which the return value will be + * expressed in terms of + * + * @return A new rectangle, equal in size to the input rectangle, but + * with its position converted from the coordinate space of the source + * component to the coordinate space of the destination component + * + * @see #convertPointToScreen + * @see #convertPointFromScreen + * @see #convertPoint + * @see #getRoot + */ + public static Rectangle convertRectangle(Component source, Rectangle rect, + Component destination) + { + Point pt = convertPoint(source, rect.x, rect.y, destination); + return new Rectangle(pt.x, pt.y, rect.width, rect.height); + } + + /** + * Convert a mouse event which refrers to one component to another. This + * includes changing the mouse event's coordinate space, as well as the + * source property of the event. If source is + * null, it is taken to refer to destination's + * root component. If destination is null, the + * new event will remain expressed in source's coordinate + * system. + * + * @param source The component the mouse event currently refers to + * @param sourceEvent The mouse event to convert + * @param destination The component the new mouse event should refer to + * + * @return A new mouse event expressed in terms of the destination + * component's coordinate space, and with the destination component as + * its source + * + * @see #convertPoint + */ + public static MouseEvent convertMouseEvent(Component source, + MouseEvent sourceEvent, + Component destination) + { + Point newpt = convertPoint(source, sourceEvent.getX(), sourceEvent.getY(), + destination); + + return new MouseEvent(destination, sourceEvent.getID(), + sourceEvent.getWhen(), sourceEvent.getModifiers(), + newpt.x, newpt.y, sourceEvent.getClickCount(), + sourceEvent.isPopupTrigger(), + sourceEvent.getButton()); + } + + + /** + * Calls {@link java.awt.EventQueue.invokeLater} with the + * specified {@link Runnable}. + */ + public static void invokeLater(Runnable doRun) + { + java.awt.EventQueue.invokeLater(doRun); + } + + /** + * Calls {@link java.awt.EventQueue.invokeAndWait} with the + * specified {@link Runnable}. + */ + public static void invokeAndWait(Runnable doRun) + throws InterruptedException, + InvocationTargetException + { + java.awt.EventQueue.invokeAndWait(doRun); + } + + /** + * Calls {@link java.awt.EventQueue.isEventDispatchThread}. + */ + public static boolean isEventDispatchThread() + { + return java.awt.EventQueue.isDispatchThread(); + } + + /** + * Returns whether the specified key code is valid. + */ + public static boolean isValidKey(int keyCode) + { + switch (keyCode) + { + case KeyEvent.VK_ENTER: + case KeyEvent.VK_BACK_SPACE: + case KeyEvent.VK_TAB: + case KeyEvent.VK_CANCEL: + case KeyEvent.VK_CLEAR: + case KeyEvent.VK_SHIFT: + case KeyEvent.VK_CONTROL: + case KeyEvent.VK_ALT: + case KeyEvent.VK_PAUSE: + case KeyEvent.VK_CAPS_LOCK: + case KeyEvent.VK_ESCAPE: + case KeyEvent.VK_SPACE: + case KeyEvent.VK_PAGE_UP: + case KeyEvent.VK_PAGE_DOWN: + case KeyEvent.VK_END: + case KeyEvent.VK_HOME: + case KeyEvent.VK_LEFT: + case KeyEvent.VK_UP: + case KeyEvent.VK_RIGHT: + case KeyEvent.VK_DOWN: + case KeyEvent.VK_COMMA: + case KeyEvent.VK_MINUS: + case KeyEvent.VK_PERIOD: + case KeyEvent.VK_SLASH: + case KeyEvent.VK_0: + case KeyEvent.VK_1: + case KeyEvent.VK_2: + case KeyEvent.VK_3: + case KeyEvent.VK_4: + case KeyEvent.VK_5: + case KeyEvent.VK_6: + case KeyEvent.VK_7: + case KeyEvent.VK_8: + case KeyEvent.VK_9: + case KeyEvent.VK_SEMICOLON: + case KeyEvent.VK_EQUALS: + case KeyEvent.VK_A: + case KeyEvent.VK_B: + case KeyEvent.VK_C: + case KeyEvent.VK_D: + case KeyEvent.VK_E: + case KeyEvent.VK_F: + case KeyEvent.VK_G: + case KeyEvent.VK_H: + case KeyEvent.VK_I: + case KeyEvent.VK_J: + case KeyEvent.VK_K: + case KeyEvent.VK_L: + case KeyEvent.VK_M: + case KeyEvent.VK_N: + case KeyEvent.VK_O: + case KeyEvent.VK_P: + case KeyEvent.VK_Q: + case KeyEvent.VK_R: + case KeyEvent.VK_S: + case KeyEvent.VK_T: + case KeyEvent.VK_U: + case KeyEvent.VK_V: + case KeyEvent.VK_W: + case KeyEvent.VK_X: + case KeyEvent.VK_Y: + case KeyEvent.VK_Z: + case KeyEvent.VK_OPEN_BRACKET: + case KeyEvent.VK_BACK_SLASH: + case KeyEvent.VK_CLOSE_BRACKET: + case KeyEvent.VK_NUMPAD0: + case KeyEvent.VK_NUMPAD1: + case KeyEvent.VK_NUMPAD2: + case KeyEvent.VK_NUMPAD3: + case KeyEvent.VK_NUMPAD4: + case KeyEvent.VK_NUMPAD5: + case KeyEvent.VK_NUMPAD6: + case KeyEvent.VK_NUMPAD7: + case KeyEvent.VK_NUMPAD8: + case KeyEvent.VK_NUMPAD9: + case KeyEvent.VK_MULTIPLY: + case KeyEvent.VK_ADD: + case KeyEvent.VK_SEPARATOR: + case KeyEvent.VK_SUBTRACT: + case KeyEvent.VK_DECIMAL: + case KeyEvent.VK_DIVIDE: + case KeyEvent.VK_DELETE: + case KeyEvent.VK_NUM_LOCK: + case KeyEvent.VK_SCROLL_LOCK: + case KeyEvent.VK_F1: + case KeyEvent.VK_F2: + case KeyEvent.VK_F3: + case KeyEvent.VK_F4: + case KeyEvent.VK_F5: + case KeyEvent.VK_F6: + case KeyEvent.VK_F7: + case KeyEvent.VK_F8: + case KeyEvent.VK_F9: + case KeyEvent.VK_F10: + case KeyEvent.VK_F11: + case KeyEvent.VK_F12: + case KeyEvent.VK_F13: + case KeyEvent.VK_F14: + case KeyEvent.VK_F15: + case KeyEvent.VK_F16: + case KeyEvent.VK_F17: + case KeyEvent.VK_F18: + case KeyEvent.VK_F19: + case KeyEvent.VK_F20: + case KeyEvent.VK_F21: + case KeyEvent.VK_F22: + case KeyEvent.VK_F23: + case KeyEvent.VK_F24: + case KeyEvent.VK_PRINTSCREEN: + case KeyEvent.VK_INSERT: + case KeyEvent.VK_HELP: + case KeyEvent.VK_META: + case KeyEvent.VK_BACK_QUOTE: + case KeyEvent.VK_QUOTE: + case KeyEvent.VK_KP_UP: + case KeyEvent.VK_KP_DOWN: + case KeyEvent.VK_KP_LEFT: + case KeyEvent.VK_KP_RIGHT: + case KeyEvent.VK_DEAD_GRAVE: + case KeyEvent.VK_DEAD_ACUTE: + case KeyEvent.VK_DEAD_CIRCUMFLEX: + case KeyEvent.VK_DEAD_TILDE: + case KeyEvent.VK_DEAD_MACRON: + case KeyEvent.VK_DEAD_BREVE: + case KeyEvent.VK_DEAD_ABOVEDOT: + case KeyEvent.VK_DEAD_DIAERESIS: + case KeyEvent.VK_DEAD_ABOVERING: + case KeyEvent.VK_DEAD_DOUBLEACUTE: + case KeyEvent.VK_DEAD_CARON: + case KeyEvent.VK_DEAD_CEDILLA: + case KeyEvent.VK_DEAD_OGONEK: + case KeyEvent.VK_DEAD_IOTA: + case KeyEvent.VK_DEAD_VOICED_SOUND: + case KeyEvent.VK_DEAD_SEMIVOICED_SOUND: + case KeyEvent.VK_AMPERSAND: + case KeyEvent.VK_ASTERISK: + case KeyEvent.VK_QUOTEDBL: + case KeyEvent.VK_LESS: + case KeyEvent.VK_GREATER: + case KeyEvent.VK_BRACELEFT: + case KeyEvent.VK_BRACERIGHT: + case KeyEvent.VK_AT: + case KeyEvent.VK_COLON: + case KeyEvent.VK_CIRCUMFLEX: + case KeyEvent.VK_DOLLAR: + case KeyEvent.VK_EURO_SIGN: + case KeyEvent.VK_EXCLAMATION_MARK: + case KeyEvent.VK_INVERTED_EXCLAMATION_MARK: + case KeyEvent.VK_LEFT_PARENTHESIS: + case KeyEvent.VK_NUMBER_SIGN: + case KeyEvent.VK_PLUS: + case KeyEvent.VK_RIGHT_PARENTHESIS: + case KeyEvent.VK_UNDERSCORE: + case KeyEvent.VK_FINAL: + case KeyEvent.VK_CONVERT: + case KeyEvent.VK_NONCONVERT: + case KeyEvent.VK_ACCEPT: + case KeyEvent.VK_MODECHANGE: + case KeyEvent.VK_KANA: + case KeyEvent.VK_KANJI: + case KeyEvent.VK_ALPHANUMERIC: + case KeyEvent.VK_KATAKANA: + case KeyEvent.VK_HIRAGANA: + case KeyEvent.VK_FULL_WIDTH: + case KeyEvent.VK_HALF_WIDTH: + case KeyEvent.VK_ROMAN_CHARACTERS: + case KeyEvent.VK_ALL_CANDIDATES: + case KeyEvent.VK_PREVIOUS_CANDIDATE: + case KeyEvent.VK_CODE_INPUT: + case KeyEvent.VK_JAPANESE_KATAKANA: + case KeyEvent.VK_JAPANESE_HIRAGANA: + case KeyEvent.VK_JAPANESE_ROMAN: + case KeyEvent.VK_KANA_LOCK: + case KeyEvent.VK_INPUT_METHOD_ON_OFF: + case KeyEvent.VK_CUT: + case KeyEvent.VK_COPY: + case KeyEvent.VK_PASTE: + case KeyEvent.VK_UNDO: + case KeyEvent.VK_AGAIN: + case KeyEvent.VK_FIND: + case KeyEvent.VK_PROPS: + case KeyEvent.VK_STOP: + case KeyEvent.VK_COMPOSE: + case KeyEvent.VK_ALT_GRAPH: + case KeyEvent.VK_BEGIN: + case KeyEvent.VK_CONTEXT_MENU: + case KeyEvent.VK_WINDOWS: + return true; + default: + return false; + } + } +} diff --git a/libjava/classpath/gnu/java/awt/BitMaskExtent.java b/libjava/classpath/gnu/java/awt/BitMaskExtent.java new file mode 100644 index 000000000..be66fccc6 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/BitMaskExtent.java @@ -0,0 +1,79 @@ +/* Copyright (C) 2000, 2002 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt; + +/** + * Simple transparent utility class that can be used to perform bit + * mask extent calculations. + */ +public final class BitMaskExtent +{ + /** The number of the least significant bit of the bit mask extent. */ + public byte leastSignificantBit; + + /** The number of bits in the bit mask extent. */ + public byte bitWidth; + + /** + * Set the bit mask. This will calculate and set the leastSignificantBit + * and bitWidth fields. + * + * @see #leastSignificantBit + * @see #bitWidth + */ + public void setMask(long mask) + { + leastSignificantBit = 0; + bitWidth = 0; + if (mask == 0) return; + long shiftMask = mask; + for (; (shiftMask&1) == 0; shiftMask >>>=1) leastSignificantBit++; + for (; (shiftMask&1) != 0; shiftMask >>>=1) bitWidth++; + + if (shiftMask != 0) + throw new IllegalArgumentException("mask must be continuous"); + } + + /** + * Calculate the bit mask based on the values of the + * leastSignificantBit and bitWidth fields. + */ + public long toMask() + { + return ((1<not implement the Porter-Duff + * XOR operator, but an exclusive or of overlapping subpixel regions. + * + *

A screen shot of BitwiseXORComposite in action + * + *

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

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

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

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

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

Applying this CompositeContext on a 1024x1024 BufferedImage of + * TYPE_INT_RGB took 69 ms on a lightly loaded 2.4 GHz + * Intel Pentium 4 CPU running Sun J2SE 1.4.1_01 on GNU/Linux + * 2.4.20. The timing is the average of ten runs on the same + * BufferedImage. Since the measurements were taken with {@link + * System#currentTimeMillis()}, they are rather inaccurate. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + private static class IntContext + extends GeneralContext + { + public IntContext(ColorModel colorModel, Color xorColor) + { + super(colorModel, colorModel, xorColor); + } + + + public void compose(Raster src, Raster dstIn, + WritableRaster dstOut) + { + int aX, bX, dstX, aY, bY, dstY, width, height; + int xorPixel; + int[] srcLine, dstLine; + + aX = src.getMinX(); + aY = src.getMinY(); + bX = dstIn.getMinX(); + bY = dstIn.getMinY(); + dstX = dstOut.getMinX(); + dstY = dstOut.getMinY(); + width = Math.min(Math.min(src.getWidth(), dstIn.getWidth()), + dstOut.getWidth()); + height = Math.min(Math.min(src.getHeight(), dstIn.getHeight()), + dstOut.getHeight()); + if ((width < 1) || (height < 1)) + return; + + srcLine = new int[width]; + dstLine = new int[width]; + + /* We need an int[] array with at least one element here; + * srcLine is as good as any other. + */ + srcColorModel.getDataElements(this.xorColor.getRGB(), srcLine); + xorPixel = srcLine[0]; + + for (int y = 0; y < height; y++) + { + src.getDataElements(aX, y + aY, width, 1, srcLine); + dstIn.getDataElements(bX, y + bY, width, 1, dstLine); + + for (int x = 0; x < width; x++) + dstLine[x] ^= srcLine[x] ^ xorPixel; + + dstOut.setDataElements(dstX, y + dstY, width, 1, dstLine); + } + } + + + /** + * Determines whether an instance of this CompositeContext would + * be able to process the specified color models. + */ + public static boolean isSupported(ColorModel srcColorModel, + ColorModel dstColorModel, + RenderingHints hints) + { + // FIXME: It would be good if someone could review these checks. + // They probably need to be more restrictive. + + int transferType; + + transferType = srcColorModel.getTransferType(); + if (transferType != dstColorModel.getTransferType()) + return false; + + if (transferType != DataBuffer.TYPE_INT) + return false; + + return true; + } + } +} diff --git a/libjava/classpath/gnu/java/awt/Buffers.java b/libjava/classpath/gnu/java/awt/Buffers.java new file mode 100644 index 000000000..0c8d438c7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/Buffers.java @@ -0,0 +1,225 @@ +/* Buffers.java -- + Copyright (C) 2000, 2002, 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt; + +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferByte; +import java.awt.image.DataBufferDouble; +import java.awt.image.DataBufferFloat; +import java.awt.image.DataBufferInt; +import java.awt.image.DataBufferShort; +import java.awt.image.DataBufferUShort; + +/** + * Utility class for creating and accessing data buffers of arbitrary + * data types. + */ +public final class Buffers +{ + /** + * Create a data buffer of a particular type. + * + * @param dataType the desired data type of the buffer. + * @param data an array containing data, or null + * @param size the size of the data buffer bank + */ + public static DataBuffer createBuffer(int dataType, Object data, + int size) + { + if (data == null) return createBuffer(dataType, size, 1); + + return createBufferFromData(dataType, data, size); + } + + + /** + * Create a data buffer of a particular type. + * + * @param dataType the desired data type of the buffer. + * @param size the size of the data buffer bank + */ + public static DataBuffer createBuffer(int dataType, int size) { + return createBuffer(dataType, size, 1); + } + + /** + * Create a data buffer of a particular type. + * + * @param dataType the desired data type of the buffer. + * @param size the size of the data buffer bank + * @param numBanks the number of banks the buffer should have + */ + public static DataBuffer createBuffer(int dataType, int size, int numBanks) + { + switch (dataType) + { + case DataBuffer.TYPE_BYTE: + return new DataBufferByte(size, numBanks); + case DataBuffer.TYPE_SHORT: + return new DataBufferShort(size, numBanks); + case DataBuffer.TYPE_USHORT: + return new DataBufferUShort(size, numBanks); + case DataBuffer.TYPE_INT: + return new DataBufferInt(size, numBanks); + case DataBuffer.TYPE_FLOAT: + return new DataBufferFloat(size, numBanks); + case DataBuffer.TYPE_DOUBLE: + return new DataBufferDouble(size, numBanks); + default: + throw new UnsupportedOperationException(); + } + } + + /** + * Create a data buffer of a particular type. + * + * @param dataType the desired data type of the buffer + * @param data an array containing the data + * @param size the size of the data buffer bank + */ + public static DataBuffer createBufferFromData(int dataType, Object data, + int size) + { + switch (dataType) + { + case DataBuffer.TYPE_BYTE: + return new DataBufferByte((byte[]) data, size); + case DataBuffer.TYPE_SHORT: + return new DataBufferShort((short[]) data, size); + case DataBuffer.TYPE_USHORT: + return new DataBufferUShort((short[]) data, size); + case DataBuffer.TYPE_INT: + return new DataBufferInt((int[]) data, size); + case DataBuffer.TYPE_FLOAT: + return new DataBufferFloat((float[]) data, size); + case DataBuffer.TYPE_DOUBLE: + return new DataBufferDouble((double[]) data, size); + default: + throw new UnsupportedOperationException(); + } + } + + /** + * Return the data array of a data buffer, regardless of the data + * type. + * + * @return an array of primitive values. The actual array type + * depends on the data type of the buffer. + */ + public static Object getData(DataBuffer buffer) + { + return getData(buffer, 0, null, 0, buffer.getSize()); + } + + + /** + * Copy data from array contained in data buffer, much like + * System.arraycopy. Create a suitable destination array if the + * given destination array is null. + */ + public static Object getData(DataBuffer src, int srcOffset, + Object dest, int dstOffset, + int length) + { + Object from; + switch(src.getDataType()) + { + case DataBuffer.TYPE_BYTE: + if (dest == null) dest = new byte[length+dstOffset]; + for(int i = 0; i < length; i++) + ((byte[])dest)[i + dstOffset] = (byte)src.getElem(i + srcOffset); + break; + + case DataBuffer.TYPE_DOUBLE: + if (dest == null) dest = new double[length+dstOffset]; + for(int i = 0; i < length; i++) + ((double[])dest)[i + dstOffset] = src.getElemDouble(i + srcOffset); + break; + + case DataBuffer.TYPE_FLOAT: + if (dest == null) dest = new float[length+dstOffset]; + for(int i = 0; i < length; i++) + ((float[])dest)[i + dstOffset] = src.getElemFloat(i + srcOffset); + break; + + case DataBuffer.TYPE_INT: + if (dest == null) dest = new int[length+dstOffset]; + for(int i = 0; i < length; i++) + ((int[])dest)[i + dstOffset] = src.getElem(i + srcOffset); + break; + + case DataBuffer.TYPE_SHORT: + case DataBuffer.TYPE_USHORT: + if (dest == null) dest = new short[length+dstOffset]; + for(int i = 0; i < length; i++) + ((short[])dest)[i + dstOffset] = (short)src.getElem(i + srcOffset); + break; + + case DataBuffer.TYPE_UNDEFINED: + throw new ClassCastException("Unknown data buffer type"); + } + return dest; + } + + /** + * @param bits the width of a data element measured in bits + * + * @return the smallest data type that can store data elements of + * the given number of bits, without any truncation. + */ + public static int smallestAppropriateTransferType(int bits) + { + if (bits <= 8) + { + return DataBuffer.TYPE_BYTE; + } + else if (bits <= 16) + { + return DataBuffer.TYPE_USHORT; + } + else if (bits <= 32) + { + return DataBuffer.TYPE_INT; + } + else + { + return DataBuffer.TYPE_UNDEFINED; + } + } +} diff --git a/libjava/classpath/gnu/java/awt/ClasspathGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/ClasspathGraphicsEnvironment.java new file mode 100644 index 000000000..fecefa03e --- /dev/null +++ b/libjava/classpath/gnu/java/awt/ClasspathGraphicsEnvironment.java @@ -0,0 +1,67 @@ +/* ClasspathGraphicsEnvironment.java + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt; + +import java.awt.GraphicsEnvironment; +import java.awt.image.ColorModel; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; + +/** + * This class extends the GraphicsEnvironment API with some Classpath-specific + * methods, in order to provide optimized graphics handling. + * + * @author Francis Kung + */ +public abstract class ClasspathGraphicsEnvironment + extends GraphicsEnvironment +{ + /** + * Returns an appropriate Raster that can efficiently back a + * BufferedImage with the given ColorModel and SampleModel. + * + * @param cm The color model. + * @param sm The samepl model. + * @return An appropriate WritableRaster, or null if acceleration/optimization + * is not available for the given colour model / sample model. + */ + public WritableRaster createRaster(ColorModel cm, SampleModel sm) + { + return null; + } +} diff --git a/libjava/classpath/gnu/java/awt/ClasspathToolkit.java b/libjava/classpath/gnu/java/awt/ClasspathToolkit.java new file mode 100644 index 000000000..99c186aaa --- /dev/null +++ b/libjava/classpath/gnu/java/awt/ClasspathToolkit.java @@ -0,0 +1,231 @@ +/* ClasspathToolkit.java -- Abstract superclass for Classpath toolkits. + Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt; + +import gnu.java.awt.peer.ClasspathDesktopPeer; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.peer.EmbeddedWindowPeer; +import gnu.java.security.action.SetAccessibleAction; + +import java.awt.AWTException; +import java.awt.Desktop; +import java.awt.Font; +import java.awt.FontFormatException; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Toolkit; +import java.awt.peer.DesktopPeer; +import java.awt.peer.RobotPeer; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.security.AccessController; +import java.util.Map; + +import javax.imageio.spi.IIORegistry; + +/** + * An abstract superclass for Classpath toolkits. + * + *

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

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

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

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

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

+ + + diff --git a/libjava/classpath/gnu/java/awt/dnd/GtkMouseDragGestureRecognizer.java b/libjava/classpath/gnu/java/awt/dnd/GtkMouseDragGestureRecognizer.java new file mode 100644 index 000000000..4ef8c2918 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/dnd/GtkMouseDragGestureRecognizer.java @@ -0,0 +1,172 @@ +/* GtkMouseDragGestureRecognizer.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.dnd; + +import java.awt.Component; +import java.awt.Point; +import java.awt.dnd.DnDConstants; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragSource; +import java.awt.dnd.MouseDragGestureRecognizer; +import java.awt.event.MouseEvent; + +public class GtkMouseDragGestureRecognizer + extends MouseDragGestureRecognizer +{ + + public GtkMouseDragGestureRecognizer (DragSource ds) + { + this(ds, null, 0, null); + } + + public GtkMouseDragGestureRecognizer (DragSource ds, Component c) + { + this (ds, c, 0, null); + } + + public GtkMouseDragGestureRecognizer (DragSource ds, Component c, int act) + { + this(ds, c, act, null); + } + + public GtkMouseDragGestureRecognizer (DragSource ds, Component c, int act, + DragGestureListener dgl) + { + super(ds, c, act, dgl); + } + + public void registerListeners () + { + super.registerListeners(); + } + + public void unregisterListeners () + { + super.unregisterListeners(); + } + + public void mouseClicked (MouseEvent e) + { + // Nothing to do here. + } + + public void mousePressed (MouseEvent e) + { + events.clear(); + if (getDropActionFromEvent(e) != DnDConstants.ACTION_NONE) + appendEvent(e); + } + + public void mouseReleased (MouseEvent e) + { + events.clear(); + } + + public void mouseEntered (MouseEvent e) + { + events.clear(); + } + + public void mouseExited(MouseEvent e) + { + if (!events.isEmpty()) + if (getDropActionFromEvent(e) == DnDConstants.ACTION_NONE) + events.clear(); + } + + public void mouseDragged(MouseEvent e) + { + if (!events.isEmpty()) + { + int act = getDropActionFromEvent(e); + + if (act == DnDConstants.ACTION_NONE) + return; + + Point origin = ((MouseEvent) events.get(0)).getPoint(); + Point current = e.getPoint(); + int dx = Math.abs(origin.x - current.x); + int dy = Math.abs(origin.y - current.y); + int threshold = DragSource.getDragThreshold(); + + if (dx > threshold || dy > threshold) + fireDragGestureRecognized(act, origin); + else + appendEvent(e); + } + } + + public void mouseMoved (MouseEvent e) + { + // Nothing to do here. + } + + private int getDropActionFromEvent(MouseEvent e) + { + int modEx = e.getModifiersEx(); + int buttons = modEx & (MouseEvent.BUTTON1_DOWN_MASK + | MouseEvent.BUTTON2_DOWN_MASK | MouseEvent.BUTTON3_DOWN_MASK); + if (!(buttons == MouseEvent.BUTTON1_DOWN_MASK || + buttons == MouseEvent.BUTTON2_DOWN_MASK)) + return DnDConstants.ACTION_NONE; + + // Convert modifier to a drop action + int sourceActions = getSourceActions(); + int mod = modEx + & (MouseEvent.SHIFT_DOWN_MASK | MouseEvent.CTRL_DOWN_MASK); + switch (mod) + { + case MouseEvent.SHIFT_DOWN_MASK | MouseEvent.CTRL_DOWN_MASK: + return DnDConstants.ACTION_LINK & sourceActions; + case MouseEvent.CTRL_DOWN_MASK: + return DnDConstants.ACTION_COPY & sourceActions; + case MouseEvent.SHIFT_DOWN_MASK: + return DnDConstants.ACTION_MOVE & sourceActions; + default: + if ((sourceActions & DnDConstants.ACTION_MOVE) != 0) + return DnDConstants.ACTION_MOVE & sourceActions; + else if ((sourceActions & DnDConstants.ACTION_COPY) != 0) + return DnDConstants.ACTION_COPY & sourceActions; + else if ((sourceActions & DnDConstants.ACTION_LINK) != 0) + return DnDConstants.ACTION_LINK & sourceActions; + } + + return DnDConstants.ACTION_NONE & sourceActions; + } +} diff --git a/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java new file mode 100644 index 000000000..4d1097626 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDragSourceContextPeer.java @@ -0,0 +1,184 @@ +/* GtkDragSourceContextPeer.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.dnd.peer.gtk; + +import gnu.java.awt.peer.gtk.GtkGenericPeer; + +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Image; +import java.awt.Point; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragSourceContext; +import java.awt.dnd.DragSourceDragEvent; +import java.awt.dnd.DragSourceDropEvent; +import java.awt.dnd.DragSourceEvent; +import java.awt.dnd.InvalidDnDOperationException; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.peer.ComponentPeer; +import java.awt.peer.LightweightPeer; + +public class GtkDragSourceContextPeer + extends GtkGenericPeer + implements DragSourceContextPeer +{ + private ComponentPeer peer; + private Cursor cursor; + private DragSourceContext context; + public static Component target; + + native void nativeStartDrag(Image i, int x, int y, int action, String target); + native void connectSignals(ComponentPeer comp); + native void create(ComponentPeer comp); + native void nativeSetCursor(int cursor); + native void setTarget(GtkDropTargetContextPeer target); + + public GtkDragSourceContextPeer(DragGestureEvent e) + { + super(e.getComponent()); + Component comp = e.getComponent(); + peer = getComponentPeer(comp); + + create(peer); + connectSignals(peer); + cursor = comp.getCursor(); + + // FIXME: Where do we set the target? + + if ((target != null)) + setTarget(new GtkDropTargetContextPeer(target)); + } + + ComponentPeer getComponentPeer(Component c) + { + if (c == null) + return null; + + Component curr = c; + while (curr.getPeer() instanceof LightweightPeer) + curr = curr.getParent(); + + if (curr != null) + return curr.getPeer(); + return null; + } + + public void startDrag(DragSourceContext context, Cursor c, Image i, Point p) + throws InvalidDnDOperationException + { + this.context = context; + + if (p == null) + p = new Point(); + + // FIXME: use proper DataFlavor, not "text/plain". + // Also, add check to determine if dragging. + + setCursor(c); + nativeStartDrag(i, p.x, p.y, context.getTrigger().getDragAction(), + "text/plain"); + } + + public Cursor getCursor() + { + return cursor; + } + + public void setCursor(Cursor c) throws InvalidDnDOperationException + { + if (c != null) + { + nativeSetCursor(c.getType()); + cursor = c; + } + } + + public void transferablesFlavorsChanged() + { + // Nothing to do here. + } + + /** + * Called from native code. + */ + + public void dragEnter(int action, int modifiers) + { + context.dragEnter(new DragSourceDragEvent(context, action, + action + & context.getSourceActions(), + modifiers)); + } + + public void dragExit(int action, int x, int y) + { + context.dragExit(new DragSourceEvent(context, x, y)); + } + + public void dragDropEnd(int action, boolean success, int x, int y) + { + context.dragDropEnd(new DragSourceDropEvent(context, action, success, x, y)); + } + + public void dragMouseMoved(int action, int modifiers) + { + context.dragMouseMoved(new DragSourceDragEvent(context, + action, + action + & context.getSourceActions(), + modifiers)); + } + + public void dragOver(int action, int modifiers) + { + context.dragOver(new DragSourceDragEvent(context, action, + action + & context.getSourceActions(), + modifiers)); + } + + public void dragActionChanged(int newAction, int modifiers) + { + context.dropActionChanged(new DragSourceDragEvent(context, + newAction, + newAction + & context.getSourceActions(), + modifiers)); + } +} diff --git a/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java new file mode 100644 index 000000000..315a2bdf1 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetContextPeer.java @@ -0,0 +1,125 @@ +/* GtkDropTargetContextPeer.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.dnd.peer.gtk; + +import gnu.java.awt.peer.gtk.GtkGenericPeer; + +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.Transferable; +import java.awt.dnd.DropTarget; +import java.awt.dnd.InvalidDnDOperationException; +import java.awt.dnd.peer.DropTargetContextPeer; + +public class GtkDropTargetContextPeer + extends GtkGenericPeer + implements DropTargetContextPeer +{ + + public GtkDropTargetContextPeer(Object obj) + { + super(obj); + } + + public void setTargetActions(int actions) + { + // FIXME: Not Implemented + + } + + public int getTargetActions() + { + // FIXME: Not Implemented + return 0; + } + + public DropTarget getDropTarget() + { + // FIXME: Not Implemented + return null; + } + + public DataFlavor[] getTransferDataFlavors() + { + // FIXME: Not Implemented + return null; + } + + public Transferable getTransferable() throws InvalidDnDOperationException + { + // FIXME: Not Implemented + return null; + } + + public boolean isTransferableJVMLocal() + { + // FIXME: Not Implemented + return false; + } + + public void acceptDrag(int dragAction) + { + // FIXME: Not Implemented + + } + + public void rejectDrag() + { + // FIXME: Not Implemented + + } + + public void acceptDrop(int dropAction) + { + // FIXME: Not Implemented + + } + + public void rejectDrop() + { + // FIXME: Not Implemented + + } + + public void dropComplete(boolean success) + { + // FIXME: Not Implemented + + } + +} diff --git a/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetPeer.java b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetPeer.java new file mode 100644 index 000000000..0799df5ba --- /dev/null +++ b/libjava/classpath/gnu/java/awt/dnd/peer/gtk/GtkDropTargetPeer.java @@ -0,0 +1,68 @@ +/* GtkDropTargetPeer.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.dnd.peer.gtk; + +import gnu.java.awt.peer.gtk.GtkGenericPeer; + +import java.awt.dnd.DropTarget; +import java.awt.dnd.peer.DropTargetPeer; + +public class GtkDropTargetPeer + extends GtkGenericPeer + implements DropTargetPeer +{ + + public GtkDropTargetPeer() + { + super(null); + } + + public void addDropTarget(DropTarget target) + { + // FIXME: Not Implemented + + } + + public void removeDropTarget(DropTarget target) + { + // FIXME: Not Implemented + + } + +} diff --git a/libjava/classpath/gnu/java/awt/doc-files/BitwiseXORComposite-1.png b/libjava/classpath/gnu/java/awt/doc-files/BitwiseXORComposite-1.png new file mode 100644 index 000000000..588c910dd Binary files /dev/null and b/libjava/classpath/gnu/java/awt/doc-files/BitwiseXORComposite-1.png differ diff --git a/libjava/classpath/gnu/java/awt/font/FontDelegate.java b/libjava/classpath/gnu/java/awt/font/FontDelegate.java new file mode 100644 index 000000000..e5c03a10f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/FontDelegate.java @@ -0,0 +1,329 @@ +/* FontDelegate.java -- Interface implemented by all font delegates. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.font; + +import java.awt.Font; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.text.CharacterIterator; +import java.util.Locale; + + +/** + * The interface that all font delegate objects implement, + * irrespective of where they get their information from. + * + *

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

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

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

+ * + *

This situation would occur for an OpenType or TrueType font + * that has a post table of format 3 and provides a + * mapping from glyph IDs to Unicode sequences through a + * Zapf table. If the same sequence of Unicode + * codepoints leads to different glyphs (depending on contextual + * position, for example, or on typographic sophistication level), + * the same name would get synthesized for those glyphs. + * + * @param glyphIndex the glyph whose name the caller wants to + * retrieve. + */ + public String getGlyphName(int glyphIndex); + + + /** + * Determines the distance between the base line and the highest + * ascender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialiased true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the ascent, which usually is a positive number. + */ + public float getAscent(float pointSize, + AffineTransform transform, + boolean antialiased, + boolean fractionalMetrics, + boolean horizontal); + + + /** + * Determines the distance between the base line and the lowest + * descender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialiased true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the descent, which usually is a nagative number. + */ + public float getDescent(float pointSize, + AffineTransform transform, + boolean antialiased, + boolean fractionalMetrics, + boolean horizontal); +} diff --git a/libjava/classpath/gnu/java/awt/font/FontFactory.java b/libjava/classpath/gnu/java/awt/font/FontFactory.java new file mode 100644 index 000000000..53eb5df5f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/FontFactory.java @@ -0,0 +1,90 @@ +/* FontFactory.java -- Factory for font delegates. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.font; + +import java.nio.ByteBuffer; + +import java.awt.FontFormatException; +import gnu.java.awt.font.opentype.OpenTypeFontFactory; + + +/** + * A factory for creating font delegate objects. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public final class FontFactory +{ + /** + * The constructor is private so nobody can construct an instance + */ + private FontFactory() + { + } + + + /** + * Creates FontDelegate objects for the fonts in the specified buffer. + * The following font formats are currently recognized: + * recognized font formats are: + * + *

+ * + *

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

The implementation reads data from the buffer only when + * needed. Therefore, it greatly increases efficiency if + * buf has been obtained through mapping a file into + * the virtual address space. + * + * @throws FontFormatException if the font data is not in one of the + * known formats. + */ + public static FontDelegate[] createFonts(ByteBuffer buf) + throws FontFormatException + { + return OpenTypeFontFactory.createFonts(buf); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/GNUGlyphVector.java b/libjava/classpath/gnu/java/awt/font/GNUGlyphVector.java new file mode 100644 index 000000000..9fd80e79e --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/GNUGlyphVector.java @@ -0,0 +1,663 @@ +/* GNUGlyphVector.java -- The GNU implementation of GlyphVector. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.font; + +import gnu.java.awt.java2d.ShapeWrapper; + +import java.awt.Font; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphMetrics; +import java.awt.font.GlyphJustificationInfo; +import java.awt.font.GlyphVector; + +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + + +/** + * The GNU implementation of the abstract GlyphVector class, which + * uses the services provided by a FontDelegate for its functionality. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class GNUGlyphVector + extends GlyphVector +{ + private FontDelegate fontDelegate; + private Font font; + private FontRenderContext renderContext; + private int[] glyphs; + private float fontSize; + private AffineTransform transform; + private boolean valid; + + + /** + * The position of each glyph. The horizontal position of the + * i-th glyph is at pos[i * 2], its + * vertical position at pos[i * 2 + 1]. The total + * advance width of the entire vector is stored at + * pos[numGlyphs], the total advance height at + * pos[numGlyphs + 1]. + */ + private float[] pos; + + + private AffineTransform[] transforms; + private int layoutFlags; + + /** + * The cached non-transformed outline of this glyph vector. + */ + private Shape cleanOutline; + + /** + * Constructs a new GNUGlyphVector. + * + * @param fontDelegate the FontDelegate that creates this vector. + * + * @param font the Font that this GlyphVector will return for {@link + * #getFont()}. That object is also used to determine the point + * size, which affects the affine transformation used by the font + * scaler. + * + * @param renderContext an object with parameters for font + * rendering, such as whether anti-aliasing is enabled. + * + * @param glyphs the glyphs in this vector. + */ + public GNUGlyphVector(FontDelegate fontDelegate, + Font font, + FontRenderContext renderContext, + int[] glyphs) + { + this.fontDelegate = fontDelegate; + this.font = font; + this.renderContext = renderContext; + this.glyphs = glyphs; + + fontSize = font.getSize2D(); + transform = font.getTransform(); // returns a modifiable copy + //transform.concatenate(renderContext.getTransform()); + } + + + + /** + * Returns the font of the glyphs in this GlyphVector. + */ + public Font getFont() + { + return font; + } + + + /** + * Returns the FontRenderContext that is used to calculate the + * extent and position of the glyphs. + */ + public FontRenderContext getFontRenderContext() + { + return renderContext; + } + + + /** + * Moves each glyph in the vector to its default position. + */ + public void performDefaultLayout() + { + float x, y, advanceWidth, advanceHeight; + int i, p; + AffineTransform tx; + Point2D.Float advance = new Point2D.Float(); + + pos = new float[(glyphs.length + 1) * 2]; + x = y = 0.0f; + p = 0; + for (i = p = 0; i < glyphs.length; i++) + { + p += 2; + + if ((transforms == null) || (tx = transforms[i]) == null) + tx = this.transform; + else + { + tx = new AffineTransform(tx); + tx.concatenate(this.transform); + } + + fontDelegate.getAdvance(glyphs[i], fontSize, tx, + renderContext.isAntiAliased(), + renderContext.usesFractionalMetrics(), + /* horizontal */ true, + advance); + // FIXME: We shouldn't round here, but instead hint the metrics + // correctly. + pos[p] = x += Math.round(advance.x); + pos[p + 1] = y += advance.y; + } + valid = true; + } + + + /** + * Determines the number of glyphs in this GlyphVector. + */ + public int getNumGlyphs() + { + return glyphs.length; + } + + + /** + * Determines the glyph number by index in this vector. + * Glyph numbers are specific to each font, so two fonts + * will likely assign different numbers to the same glyph. + * + * @param glyphIndex the index of the glyph whose glyph number is to + * be retrieved. + * + * @throws IndexOutOfBoundsException if glyphIndex + * is not in the range . + */ + public int getGlyphCode(int glyphIndex) + { + /* The exception is thrown automatically if the index is out + * of the valid bounds. + */ + return glyphs[glyphIndex]; + } + + + /** + * Returns a slice of this GlyphVector. + * + * @param firstGlyphIndex the index of the first glyph in the + * returned slice. + * + * @param numEntries the size of the returned slice. + * + * @param outCodes a pre-allocated array for storing the slice, + * or null to cause allocation of a new array. + * + * @return a slice of this GlyphVector. If outCodes + * is null, the slice will be stored into a freshly + * allocated array; otherwise, the result will be stored into + * outCodes. + */ + public int[] getGlyphCodes(int firstGlyphIndex, + int numEntries, + int[] outCodes) + { + if (numEntries < 0) + throw new IllegalArgumentException(); + if (outCodes == null) + outCodes = new int[numEntries]; + System.arraycopy(glyphs, firstGlyphIndex, outCodes, 0, numEntries); + return outCodes; + } + + + public Rectangle2D getLogicalBounds() + { + float ascent, descent; + + validate(); + + return new Rectangle2D.Float(0, 0, + pos[pos.length - 2], + getAscent() - getDescent()); + } + + + public Rectangle2D getVisualBounds() + { + validate(); + + // FIXME: Not yet implemented. + return getLogicalBounds(); + } + + + /** + * Returns the shape of this GlyphVector. + */ + public Shape getOutline() + { + return getOutline(0.0f, 0.0f); + } + + + /** + * Returns the shape of this GlyphVector, translated to the + * specified position. + * + * @param x the horizontal position for rendering this vector. + * @param y the vertical position for rendering this vector. + */ + public Shape getOutline(float x, float y) + { + validate(); + + Shape outline; + if (cleanOutline == null) + { + GeneralPath path = new GeneralPath(); + int len = glyphs.length; + for (int i = 0; i < len; i++) + { + GeneralPath p = new GeneralPath(getGlyphOutline(i)); + path.append(p, false); + } + // Protect the cached instance from beeing modified by application + // code. + cleanOutline = new ShapeWrapper(path); + outline = cleanOutline; + } + else + { + outline = cleanOutline; + } + if (x != 0 || y != 0) + { + GeneralPath path = new GeneralPath(outline); + AffineTransform t = new AffineTransform(); + t.translate(x, y); + path.transform(t); + outline = path; + } + return outline; + } + + public Shape getOutline(float x, float y, int type) + { + validate(); + + GeneralPath outline = new GeneralPath(); + int len = glyphs.length; + for (int i = 0; i < len; i++) + { + GeneralPath p = new GeneralPath(getGlyphOutline(i, type)); + outline.append(p, false); + } + AffineTransform t = new AffineTransform(); + t.translate(x, y); + outline.transform(t); + return outline; + } + + /** + * Determines the shape of the specified glyph. + * + * @throws IndexOutOfBoundsException if glyphIndex is + * not in the range . + */ + public Shape getGlyphOutline(int glyphIndex) + { + AffineTransform tx, glyphTx; + GeneralPath path; + + validate(); + + if ((transforms != null) + && ((glyphTx = transforms[glyphIndex]) != null)) + { + tx = new AffineTransform(transform); + tx.concatenate(glyphTx); + } + else + tx = transform; + + path = fontDelegate.getGlyphOutline(glyphs[glyphIndex], fontSize, tx, + renderContext.isAntiAliased(), + renderContext.usesFractionalMetrics(), + FontDelegate.FLAG_FITTED); + + tx = new AffineTransform(); + tx.translate(pos[glyphIndex * 2], pos[glyphIndex * 2 + 1]); + path.transform(tx); + return path; + } + + public Shape getGlyphOutline(int glyphIndex, int type) + { + AffineTransform tx, glyphTx; + GeneralPath path; + + validate(); + + if ((transforms != null) + && ((glyphTx = transforms[glyphIndex]) != null)) + { + tx = new AffineTransform(transform); + tx.concatenate(glyphTx); + } + else + tx = transform; + + path = fontDelegate.getGlyphOutline(glyphs[glyphIndex], fontSize, tx, + renderContext.isAntiAliased(), + renderContext.usesFractionalMetrics(), + type); + + tx = new AffineTransform(); + tx.translate(pos[glyphIndex * 2], pos[glyphIndex * 2 + 1]); + path.transform(tx); + return path; + } + + /** + * Determines the position of the specified glyph, or the + * total advance width and height of the vector. + * + * @param glyphIndex the index of the glyph in question. + * If this value equals getNumGlyphs(), the + * position after the last glyph will be returned, + * which is the total advance width and height of the vector. + * + * @throws IndexOutOfBoundsException if glyphIndex is + * not in the range . + */ + public Point2D getGlyphPosition(int glyphIndex) + { + validate(); + return new Point2D.Float(pos[glyphIndex * 2], + pos[glyphIndex * 2 + 1]); + } + + + /** + * Moves the specified glyph to a new position, or changes the + * advance width and height of the entire glyph vector. + * + *

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

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

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

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

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

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

+ * + *

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

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

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

+ */ + static boolean isSupported(int platform, int encoding) + { + switch (platform) + { + case PLATFORM_UNICODE: + return (encoding >= 0) && (encoding <= 4); + + case PLATFORM_MICROSOFT: + return (encoding == /* Basic Multilingual Plane */ 1) + || (encoding == /* Full Unicode */ 10); + } + + return false; + } + + + /** + * Constructs a cmap type 12 table whose platform and + * encoding are already known. We understand the Unicode platform + * with encodings 0, 1, 2, 3 and 4, and the Microsoft platform + * with encodings 1 (Unicode BMP) and 10 (UCS-4). + * + * @param buf the buffer to read the table from, positioned at + * its beginning. + */ + Type12(ByteBuffer buf, int platform, int encoding) + { + int tableStart = buf.position(); + int format = buf.getChar(); + if ((format != 12) || !isSupported(platform, encoding)) + throw new IllegalStateException(); + + buf.getChar(); // skip reserved field + buf.limit(tableStart + buf.getInt()); + int language = buf.getInt(); + numGroups = buf.getInt(); + data = buf.asIntBuffer(); + } + + + /** + * Determines the glyph index for a given Unicode codepoint. Users + * should be aware that the character-to-glyph mapping not not + * everything that is needed for full Unicode support. For example, + * the cmap table is not able to synthesize accented + * glyphs from the canonical decomposition sequence, even if the + * font would contain a glyph for the composed form. + * + * @param ucs4 the Unicode codepoint in UCS-4 encoding. Surrogates + * (U+D800 to U+DFFF) cannot be passed, they must be mapped to + * UCS-4 first. + * + * @return the glyph index, or 0 if the font does not contain + * a glyph for this codepoint. + */ + public int getGlyph(int ucs4) + { + int min, max, mid, startCharCode, endCharCode; + + min = 0; + max = numGroups - 1; + mid = max >> 1; + do + { + startCharCode = data.get(3 * mid); + endCharCode = data.get(3 * mid + 1); + + + /* + System.out.println("group " + mid + " (U+" + + Integer.toHexString(startCharCode) + + " .. U+" + Integer.toHexString(endCharCode) + + "): glyph " + (int) data.get(mid*3+2)); + */ + + if ((startCharCode <= ucs4) && (ucs4 <= endCharCode)) + return ucs4 + - startCharCode + + /* startGlyphID */ data.get(mid * 3 + 2); + + if (endCharCode < ucs4) + min = mid + 1; + else + max = mid; + mid = (min + max) >> 1; + } + while (min < max); + + startCharCode = data.get(3 * mid); + endCharCode = data.get(3 * mid + 1); + if ((startCharCode <= ucs4) && (ucs4 <= endCharCode)) + return ucs4 + - startCharCode + + /* startGlyphID */ data.get(mid * 3 + 2); + + return 0; + } + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/GlyphNamer.java b/libjava/classpath/gnu/java/awt/font/opentype/GlyphNamer.java new file mode 100644 index 000000000..72cecb542 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/GlyphNamer.java @@ -0,0 +1,1135 @@ +/* GlyphNamer.java -- Provides glyph names. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.font.opentype; + +import gnu.java.lang.CPStringBuilder; + +import java.nio.ByteBuffer; +import java.nio.IntBuffer; +import java.nio.CharBuffer; + + +/** + * Provides names for glyphs, which is useful when embedding fonts + * in PostScript or PDF documents. + * + *

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

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

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

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

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

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

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

Some examples: + *

. + * + *

The routine does not bring sequences in any canonical + * form. Therefore, the result for U+0067 U+0302 (the + * decomposition of U+011D) will be + * g_uni0302, not gcircumflex. + * + * @see Unicode + * and Glyph Names and Glyph Names and Current Implementations + */ + private static String getGlyphName(char[] chars) + { + char c; + String name; + int numChars; + boolean hasSurrogates = false; + + if ((chars == null) || ((numChars = chars.length) == 0)) + return ".notdef"; + + /* The vast majority of cases will be just a single character. + * Therefore, we have a special code path for this case. + */ + if (numChars == 1) + { + c = chars[0]; + name = getAGLFNName(c); + if (name != null) + return name; + } + + CPStringBuilder buf = new CPStringBuilder(numChars * 8); + for (int i = 0; i < numChars; i++) + { + if (i > 0) + buf.append('_'); + c = chars[i]; + + /* handle surrogate pairs */ + if (c >> 10 == 0x36) // U+D800 .. U+DBFF: High surrogate + { + /* Adobe recommends using the 'u' prefix only for + * characters outside the Unicode Basic Multilingual Plane, + * because Acrobat 4 and 5 understand only the "uni" prefix. + * The 'u' prefix will be supported by Acrobat 6 and later. + * + * For further information, please refer to this page: + * http://partners.adobe.com/asn/tech/type/glyphnamelimits.jsp#3 + */ + int ucs4 = (((c & 0x3ff) << 10) | (chars[++i] & 0x3ff)) + 0x10000; + buf.append('u'); + buf.append(Integer.toHexString(ucs4).toUpperCase()); + } + else + { + /* Try the Adobe Glyph List. */ + name = getAGLFNName(c); + if (name != null) + buf.append(name); + else + { + char nibble; + buf.append("uni"); + nibble = (char) (((c >> 12) & 0xf) + 0x30); + if (nibble > 0x39) + nibble += 7; + buf.append(nibble); + nibble = (char) (((c >> 8) & 0xf) + 0x30); + if (nibble > 0x39) + nibble += 7; + buf.append(nibble); + nibble = (char) (((c >> 4) & 0xf) + 0x30); + if (nibble > 0x39) + nibble += 7; + buf.append(nibble); + nibble = (char) (((c >> 0) & 0xf) + 0x30); + if (nibble > 0x39) + nibble += 7; + buf.append(nibble); + } + } + } + return buf.toString(); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/Hinter.java b/libjava/classpath/gnu/java/awt/font/opentype/Hinter.java new file mode 100644 index 000000000..9758a2896 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/Hinter.java @@ -0,0 +1,63 @@ +/* Hinter.java -- The interface to a hinting implementation + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.font.opentype; + +import gnu.java.awt.font.opentype.truetype.Zone; + +/** + * The interface to a hinting implementation. + */ +public interface Hinter +{ + /** + * Initializes the hinter. + * + * @param face the font for which the hinter should be used + */ + void init(OpenTypeFont face); + + /** + * Hints the specified outline. + * + * @param outline the outline to hint + */ + void applyHints(Zone outline); + + void setFlags(int flags); +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/MacResourceFork.java b/libjava/classpath/gnu/java/awt/font/opentype/MacResourceFork.java new file mode 100644 index 000000000..c0f3de80e --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/MacResourceFork.java @@ -0,0 +1,235 @@ +/* MacResourceFork.java -- Parses MacOS resource forks. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.font.opentype; + +import java.nio.ByteBuffer; + + +/** + * A class for accessing data that is stored in the resource fork of + * Macintosh files. Writing resource forks is currently not supported. + * + *

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

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

Thread Safety: All access is synchronized on the ByteBuffer + * that is passed to the constructor. + * + * @see Apple’ developer documentation about the Resource File + * Format + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +final class MacResourceFork +{ + int[] types; + Resource[][] resources; + ByteBuffer buf; + + public MacResourceFork(ByteBuffer buf) + { + int typeListOffset; + int refListOffset; + int nameListOffset; + int mapOffset, mapLen; + int dataOffset, dataLen; + int numTypes; + + synchronized (buf) + { + buf = buf.duplicate(); + this.buf = buf; + buf.position(0); + dataOffset = buf.getInt(); + mapOffset = buf.getInt(); + dataLen = buf.getInt(); + mapLen = buf.getInt(); + buf.position(mapOffset + 24); + refListOffset = mapOffset + buf.getChar(); + nameListOffset = mapOffset + buf.getChar(); + numTypes = buf.getChar() + 1; + types = new int[numTypes]; + resources = new Resource[numTypes][]; + + /* Parse resource type list. */ + typeListOffset = buf.position(); + for (int i = 0; i < numTypes; i++) + { + buf.position(typeListOffset + 8 * i); + int resType = buf.getInt(); + int numRes = buf.getChar() + 1; + + types[i] = resType; + resources[i] = new Resource[numRes]; + + buf.position(refListOffset + buf.getChar()); + for (int j = 0; j < numRes; j++) + { + short resID = buf.getShort(); + int resNameOffset = nameListOffset + buf.getChar(); + int resDataOffset = buf.getInt(); + byte resAttr = (byte) (resDataOffset >> 24); + resDataOffset = dataOffset + (resDataOffset & 0x00ffffff); + buf.getInt(); /* skip four reserved bytes */ + + Resource rsrc = new Resource(buf, resType, resID, resDataOffset, + resNameOffset); + resources[i][j] = rsrc; + } + } + } + } + + + public Resource[] getResources(int type) + { + synchronized (buf) + { + for (int i = 0; i < types.length; i++) + { + if (types[i] == type) + return resources[i]; + } + } + return null; + } + + + public Resource getResource(int type, short id) + { + Resource[] res; + + synchronized (buf) + { + for (int i = 0; i < types.length; i++) + { + if (types[i] != type) + continue; + + res = resources[i]; + for (int j = 0; j < res.length; j++) + if (res[j].getID() == id) + return res[j]; + } + } + + return null; + } + + + /** + * A single resource that is contained in a resource fork. + */ + public static final class Resource + { + int type; + short id; + byte attribute; + int nameOffset; + int dataOffset; + ByteBuffer buf; + + private Resource(ByteBuffer buf, + int type, short id, int dataOffset, int nameOffset) + { + this.buf = buf; + this.type = type; + this.id = id; + this.dataOffset = dataOffset; + this.nameOffset = nameOffset; + } + + + /** + * Returns the type of this resource. + * + * @return an int encoding a four-byte type tag, + * such as 0x464f4e54 for 'FONT'. + */ + public int getType() + { + return type; + } + + + /** + * Returns the ID of this resource. + */ + public short getID() + { + return id; + } + + + /** + * Retrieves the content of the resource. Only one page of memory + * is touched, irrespective of the actual size of the resource. + */ + public ByteBuffer getContent() + { + synchronized (buf) + { + buf.limit(buf.capacity()); + int len = buf.getInt(dataOffset); + buf.position(dataOffset + 4).limit(dataOffset + 4 + len); + return buf.slice(); + } + } + + + /** + * Determines the length of the resource in bytes. + */ + public int getLength() + { + synchronized (buf) + { + return buf.getInt(dataOffset); + } + } + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/NameDecoder.java b/libjava/classpath/gnu/java/awt/font/opentype/NameDecoder.java new file mode 100644 index 000000000..1f1d50ac1 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/NameDecoder.java @@ -0,0 +1,702 @@ +/* NameDecoder.java -- Decodes names of OpenType and TrueType fonts. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.font.opentype; + +import java.io.UnsupportedEncodingException; +import java.nio.ByteBuffer; +import java.util.Locale; + + +/** + * A utility class that helps with decoding the names of OpenType + * and TrueType fonts. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public class NameDecoder +{ + public static final int NAME_COPYRIGHT = 0; + + + /** + * Specifies the name of the family to which a font belongs, for + * example “Univers”. + */ + public static final int NAME_FAMILY = 1; + + + /** + * Specified the name of the font inside its family, for + * example “Light”. + */ + public static final int NAME_SUBFAMILY = 2; + + + public static final int NAME_UNIQUE = 3; + + + /** + * Specifies the full human-readable name of a font, for example + * “Univers Light” + */ + public static final int NAME_FULL = 4; + + + public static final int NAME_VERSION = 5; + + + /** + * Specifies the PostScript name of a font, for example + * “Univers-Light”. + */ + public static final int NAME_POSTSCRIPT = 6; + + + public static final int NAME_TRADEMARK = 7; + public static final int NAME_MANUFACTURER = 8; + public static final int NAME_DESIGNER = 9; + public static final int NAME_DESCRIPTION = 10; + public static final int NAME_VENDOR_URL = 11; + public static final int NAME_DESIGNER_URL = 12; + public static final int NAME_LICENSE = 13; + public static final int NAME_LICENSE_URL = 14; + public static final int NAME_PREFERRED_FAMILY = 16; + public static final int NAME_PREFERRED_SUBFAMILY = 17; + public static final int NAME_FULL_MACCOMPATIBLE = 18; + public static final int NAME_SAMPLE_TEXT = 19; + public static final int NAME_POSTSCRIPT_CID = 20; + + + private static final int PLATFORM_MACINTOSH = 1; + private static final int PLATFORM_MICROSOFT = 3; + + + public static String getName(ByteBuffer nameTable, + int name, Locale locale) + { + int numRecords; + int macLanguage, msLanguage; + int offset; + int namePlatform, nameEncoding, nameLanguage, nameID, nameLen; + int nameStart; + String result; + boolean match; + + if (nameTable == null) + return null; + + nameTable.position(0); + /* We understand only format 0 of the name table. */ + if (nameTable.getShort() != 0) + return null; + + macLanguage = getMacLanguageCode(locale); + msLanguage = getMicrosoftLanguageCode(locale); + numRecords = nameTable.getShort(); + offset = nameTable.getShort(); + + for (int i = 0; i < numRecords; i++) + { + namePlatform = nameTable.getShort(); + nameEncoding = nameTable.getShort(); + nameLanguage = nameTable.getShort(); + nameID = nameTable.getShort(); + nameLen = nameTable.getShort(); + nameStart = offset + nameTable.getShort(); + + + if (nameID != name) + continue; + + // Handle PS seperately as it can be only ASCII, although + // possibly encoded as UTF-16BE + if ( name == NAME_POSTSCRIPT ) + { + if( nameTable.get(nameStart) == 0 ) // Peek at top byte + result = decodeName("UTF-16BE", nameTable, nameStart, nameLen); + else + result = decodeName("ASCII", nameTable, nameStart, nameLen); + return result; + } + + match = false; + switch (namePlatform) + { + case PLATFORM_MACINTOSH: + if ((nameLanguage == macLanguage) || (locale == null)) + match = true; + else + { + switch (macLanguage) + { + case 49: /* Azerbaijani/Cyrillic */ + match = (nameLanguage == /* Azerbaijani/Arabic */ 50) + || (nameLanguage == /* Azerbaijani/Roman */ 150); + break; + + case 57: /* Mongolian/Mongolian */ + match = (nameLanguage == /* Mongolian/Cyrillic */ 58); + break; + + case 83: /* Malay/Roman */ + match = (nameLanguage == /* Malay/Arabic */ 84); + break; + } + } + break; + + case PLATFORM_MICROSOFT: + if (((nameLanguage & 0xff) == msLanguage) || (locale == null)) + match = true; + break; + } + + + if (match) + { + result = decodeName(namePlatform, nameEncoding, nameLanguage, + nameTable, nameStart, nameLen); + if (result != null) + return result; + } + } + + return null; + } + + + /** + * The language codes used by the Macintosh operating system. MacOS + * defines numeric language identifiers in the range [0 .. 95] and + * [128 .. 150]. To map this numeric identifier into an ISO 639 + * language code, multiply it by two and take the substring at that + * position. + * + *

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

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

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

+ * + *

The following cases are problematic: + * + *

+ * + * @return a MacOS language code, or -1 if there is no such code for + * loc’s language. + */ + private static int getMacLanguageCode(Locale loc) + { + int code; + + if (loc == null) + return -1; + + code = findLanguageCode(loc.getLanguage(), macLanguageCodes); + switch (code) + { + case 19: + /* Traditional Chinese (MacOS language #19) and and Simplified + * Chinese (MacOS language #33) both have "zh" as their ISO 639 + * code. + */ + if (loc.equals(Locale.SIMPLIFIED_CHINESE)) + code = 33; + break; + + // Other special cases would be 49, 57 and 83, but we do not + // know what do do about them. See the method documentation for + // details. + } + + return code; + } + + + /** + * Maps a Java Locale into a Microsoft language code. + */ + private static int getMicrosoftLanguageCode(Locale locale) + { + String isoCode; + int code; + + if (locale == null) + return -1; + + isoCode = locale.getLanguage(); + code = findLanguageCode(isoCode, microsoftLanguageCodes); + if (code == -1) + { + if (isoCode.equals("hr") || isoCode.equals("sr")) + { + /* Microsoft uses code 26 for "sh" (Serbo-Croatian), + * "hr" (Croatian) and "sr" (Serbian). Our table contains + * "sh". + */ + code = 26; + } + else if (isoCode.equals("gd")) + { + /* Microsoft uses code 60 for "gd" (Scottish Gaelic) and + * "ga" (Irish Gaelic). Out table contains "ga". + */ + code = 60; + } + } + return code; + } + + + private static int findLanguageCode(String lang, String langCodes) + { + int index; + if (lang == null) + return -1; + + if (lang.length() != 2) + return -1; + + index = 0; + do + { + index = langCodes.indexOf(lang, index); + + /* The index must be even to be considered a match. Otherwise, we + * could match with the second letter of one language and the + * first of antoher one. + */ + } + while (!((index < 0) || ((index & 1) == 0))); + if (index < 0) + return -1; + + index = index / 2; + return index; + } + + + private static String decodeName(int platform, int encoding, int language, + ByteBuffer buffer, int offset, int len) + { + String charsetName = getCharsetName(platform, language, encoding); + if (charsetName == null) + return null; + + return decodeName(charsetName, buffer, offset, len); + } + + private static String decodeName(String charsetName, + ByteBuffer buffer, int offset, int len) + { + byte[] byteBuf; + int oldPosition; + + byteBuf = new byte[len]; + oldPosition = buffer.position(); + try + { + buffer.position(offset); + buffer.get(byteBuf); + try + { + return new String(byteBuf, charsetName); + } + catch (UnsupportedEncodingException uex) + { + } + } + finally + { + buffer.position(oldPosition); + } + + return null; + } + + + /** + * Maps a MacOS language code into a Java Locale. + * + * @param macLanguageCode the MacOS language code for + * the language whose Java locale is to be retrieved. + * + * @return an suitable Locale, or null if + * the mapping cannot be performed. + */ + private static Locale getMacLocale(int macLanguageCode) + { + String isoCode; + + switch (macLanguageCode) + { + case 0: return Locale.ENGLISH; + case 1: return Locale.FRENCH; + case 2: return Locale.GERMAN; + case 3: return Locale.ITALIAN; + case 11: return Locale.JAPANESE; + case 23: return Locale.KOREAN; + case 19: return Locale.TRADITIONAL_CHINESE; + case 33: return Locale.SIMPLIFIED_CHINESE; + } + + if ((macLanguageCode < 0) || (macLanguageCode > 150)) + return null; + + isoCode = macLanguageCodes.substring(macLanguageCode << 1, + (macLanguageCode + 1) << 1); + if (isoCode.charAt(0) == ' ') + return null; + + return new Locale(isoCode); + } + + + + /** + * Maps a Windows LCID into a Java Locale. + * + * @param lcid the Windows language ID whose Java locale + * is to be retrieved. + * + * @return an suitable Locale, or null if + * the mapping cannot be performed. + */ + private static Locale getWindowsLocale(int lcid) + { + /* FIXME: This is grossly incomplete. */ + switch (lcid) + { + case 0x0407: return Locale.GERMAN; + case 0x0408: return new Locale("el", "GR"); + case 0x0409: return Locale.ENGLISH; + case 0x040b: return new Locale("fi"); + case 0x040c: return Locale.FRENCH; + case 0x0416: return new Locale("pt"); + case 0x0807: return new Locale("de", "CH"); + case 0x0809: return new Locale("en", "UK"); + case 0x080c: return new Locale("fr", "BE"); + case 0x0816: return new Locale("pt", "BR"); + case 0x0c07: return new Locale("de", "AT"); + case 0x0c09: return new Locale("en", "AU"); + case 0x0c0c: return new Locale("fr", "CA"); + case 0x1007: return new Locale("de", "LU"); + case 0x1009: return new Locale("en", "CA"); + case 0x100c: return new Locale("fr", "CH"); + case 0x1407: return new Locale("de", "LI"); + case 0x1409: return new Locale("en", "NZ"); + case 0x140c: return new Locale("fr", "LU"); + case 0x1809: return new Locale("en", "IE"); + + default: + return null; + } + } + + + /** + * Maps a Macintosh Script Manager code to the name of the + * corresponding Java Charset. + * + * @param macScript a MacOS ScriptCode, for example + * 6 for smGreek. + * + * @return a String that can be used to retrieve a Java + * CharsetDecorder, for example MacGreek, or + * null if macScript has an + * unsupported value. + */ + private static String getMacCharsetName(int macScript) + { + switch (macScript) + { + case 0: return "MacRoman"; + case 1: return "MacJapanese"; + case 2: return "MacKorean"; + case 3: return "MacTradChinese"; + case 4: return "MacArabic"; + case 5: return "MacHebrew"; + case 6: return "MacGreek"; + case 7: return "MacCyrillic"; + case 8: return "MacRSymbol"; + case 9: return "MacDevanagari"; + case 10: return "MacGurmukhi"; + case 11: return "MacGujarati"; + case 12: return "MacOriya"; + case 13: return "MacBengali"; + case 14: return "MacTamil"; + case 15: return "MacTelugu"; + case 16: return "MacKannada"; + case 17: return "MacMalayalam"; + case 18: return "MacSinhalese"; + case 19: return "MacBurmese"; + case 20: return "MacKhmer"; + case 21: return "MacThai"; + case 22: return "MacLao"; + case 23: return "MacGeorgian"; + case 24: return "MacArmenian"; + case 25: return "MacSimpChinese"; + case 26: return "MacTibetan"; + case 27: return "MacMongolian"; + case 28: return "MacEthiopic"; + case 29: return "MacCentralEurope"; + case 30: return "MacVietnamese"; + case 31: return "MacExtArabic"; + + default: return null; + } + } + + + /** + * Maps a Microsoft locale ID (LCID) to the name of the + * corresponding Java Charset. + * + * @param lcid the Microsoft locale ID. + * + * @return a String that can be used to retrieve a Java + * CharsetDecorder, for example windows-1252, or + * null if lcid has an unsupported value. + */ + private static String getMicrosoftCharsetName(int lcid) + { + int lang; + char codePage = '?'; + + /* Extract the language code from the LCID. */ + lang = lcid & 0x3ff; + + /* In the majority of cases, the language alone determines the + * codepage. + */ + if (lang < 100) + codePage = (" 612D022322225022EC2202201?002A462110777 68 ?2 1 " + + " 2 2 2112 ?1 1 2 2 ") + .charAt(lang); + + /* There are a few exceptions, however, where multiple code pages + * are used for the same language. */ + if (codePage == '?') + { + switch (lcid) + { + case 0x041a: // Croatian --> Windows-1250 (Central Europe) + case 0x081a: // Serbian (Latin) --> Windows-1250 (Central Europe) + codePage = '0'; + break; + + case 0x42c: // Azeri (Latin) --> Windows-1254 (Turkish) + case 0x443: // Uzbek (Latin) --> Windows-1254 (Turkish) + codePage = '4'; + break; + + case 0x82c: // Azeri (Cyrillic) --> Windows-1251 (Cyrillic) + case 0x843: // Uzbek (Cyrillic) --> Windows-1251 (Cyrillic) + case 0xc1a: // Serbian (Cyrillic) --> Windows-1251 (Cyrillic) + codePage = '1'; + break; + } + } + + switch (codePage) + { + case '0': return "windows-1250"; // Central Europe + case '1': return "windows-1251"; // Cyrillic + case '2': return "windows-1252"; // Latin 1 + case '3': return "windows-1253"; // Greek + case '4': return "windows-1254"; // Turkish + case '5': return "windows-1255"; // Hebrew + case '6': return "windows-1256"; // Arabic + case '7': return "windows-1257"; // Baltic + case '8': return "windows-1258"; // Vietnam + case 'A': return "windows-874"; // Thai + case 'B': return "windows-936"; // Simplified Chinese, GBK + case 'C': return "windows-949"; // Korean + case 'D': return "windows-950"; // Traditional Chinese, Big5 + case 'E': return "windows-932"; // Japanese Shift-JIS + default: return null; + } + } + + + /** + * Returns the Locale of an OpenType name. + * + * @param platform the OpenType platform ID. + * + * @param language the language tag of the OpenType name. If + * platform is 1, this is the MacOS language code. + * + * @param encoding the encoding tag of the OpenType name. If + * platform is 1, this is the MacOS script code. + */ + public static Locale getLocale(int platform, int language, int encoding) + { + switch (platform) + { + case 1: /* Apple Macintosh */ + return getMacLocale(language); + + case 3: /* Microsoft Windows */ + return getWindowsLocale(language); + + default: + return null; + } + } + + + /** + * Determines the name of the charset for an OpenType font name. + * + * @param platform the OpenType platform ID. + * + * @param language the language tag of the OpenType name. If + * platform is 1, this is the MacOS language code. + * + * @param encoding the encoding tag of the OpenType name. If + * platform is 1, this is the MacOS script code. + * + * @return a charset name such as "MacRoman", + * or null if the combination is not known. + */ + public static String getCharsetName(int platform, int language, int encoding) + { + switch (platform) + { + case 1: /* Apple Macintosh */ + return getMacCharsetName(encoding); + + case 3: /* Microsoft Windows */ + return getMicrosoftCharsetName(language); + + default: + return null; + } + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java b/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java new file mode 100644 index 000000000..f46addc3c --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFont.java @@ -0,0 +1,882 @@ +/* OpenTypeFont.java -- Manages OpenType and TrueType fonts. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.font.opentype; + +import java.awt.Font; +import java.awt.FontFormatException; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.OpenType; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.nio.ByteBuffer; +import java.text.CharacterIterator; +import java.util.Locale; + +import gnu.java.awt.font.FontDelegate; +import gnu.java.awt.font.GNUGlyphVector; +import gnu.java.awt.font.autofit.AutoHinter; +import gnu.java.awt.font.opentype.truetype.TrueTypeScaler; +import gnu.java.awt.font.opentype.truetype.Zone; + + +/** + * A font that takes its data from OpenType or TrueType font tables. + * + *

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

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

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

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

+ * + *

This situation would occur for an OpenType or TrueType font + * that has a post table of format 3 and provides a + * mapping from glyph IDs to Unicode sequences through a + * Zapf table. If the same sequence of Unicode + * codepoints leads to different glyphs (depending on contextual + * position, for example, or on typographic sophistication level), + * the same name would get synthesized for those glyphs. + * + * @param glyphIndex the glyph whose name the caller wants to + * retrieve. + */ + public synchronized String getGlyphName(int glyphIndex) + { + if (glyphNamer == null) + glyphNamer = GlyphNamer.forTables(numGlyphs, + getFontTable(OpenType.TAG_POST), + getFontTable(TAG_ZAPF)); + + return glyphNamer.getGlyphName(glyphIndex); + } + + + /** + * Determines the distance between the base line and the highest + * ascender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialiased true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the ascent, which usually is a positive number. + */ + public synchronized float getAscent(float pointSize, + AffineTransform transform, + boolean antialiased, + boolean fractionalMetrics, + boolean horizontal) + { + return scaler.getAscent(pointSize, transform, + antialiased, fractionalMetrics, + horizontal); + } + + + /** + * Determines the distance between the base line and the lowest + * descender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialiased true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the descent, which usually is a nagative number. + */ + public synchronized float getDescent(float pointSize, + AffineTransform transform, + boolean antialiased, + boolean fractionalMetrics, + boolean horizontal) + { + return scaler.getDescent(pointSize, transform, + antialiased, fractionalMetrics, + horizontal); + } + + + /** + * Converts a four-byte tag identifier into a String that can be + * displayed when debugging this class. + * + * @param tag the tag as an int. + * + * @return the tag in human-readable form, for example + * name or glyf. + */ + static String tagToString(int tag) + { + char[] c = new char[4]; + c[0] = (char) ((tag >> 24) & 0xff); + c[1] = (char) ((tag >> 16) & 0xff); + c[2] = (char) ((tag >> 8) & 0xff); + c[3] = (char) (tag & 0xff); + return new String(c); + } + + /** + * Checks if a hinter is installed and installs one when not. + */ + private void checkHinter(int flags) + { + // When another hinting impl gets added (maybe a true TrueType hinter) + // then add some options here. The Hinter interface might need to be + // tweaked. + if (hinter == null) + { + try + { + hinter = new AutoHinter(); + hinter.init(this); + } + catch (Exception ex) + { + // Protect from problems inside hinter. + hinter = null; + ex.printStackTrace(); + } + } + hinter.setFlags(flags); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFontFactory.java b/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFontFactory.java new file mode 100644 index 000000000..32c4828c9 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/OpenTypeFontFactory.java @@ -0,0 +1,140 @@ +/* OpenTypeFontFactory.java -- Creates OpenType and TrueType fonts. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.font.opentype; + +import gnu.java.awt.font.FontDelegate; +import java.awt.FontFormatException; +import java.awt.font.OpenType; +import java.nio.ByteBuffer; + + +/** + * A factory for creating fonts that are stored in an + * sfnt-housed format, for example OpenType or TrueType. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public final class OpenTypeFontFactory +{ + /** + * The constructor is private so nobody can construct an instance + * of this class. + */ + private OpenTypeFontFactory() + { + } + + + /** + * Creates FontDelegate objects for the fonts in the specified + * buffer. The following font formats are currently recognized: + * + *

+ * + *

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

The implementation reads data from the buffer only when + * needed. Therefore, it greatly increases efficiency if + * buf has been obtained through mapping a file into + * the virtual address space. + * + * @throws FontFormatException if the font data is not in one of the + * known formats. + */ + public static FontDelegate[] createFonts(ByteBuffer buf) + throws FontFormatException + { + OpenTypeFont[] fonts; + int version; + + version = buf.getInt(0); + switch (version) + { + case 0x00010000: // Microsoft Windows TrueType + case OpenType.TAG_TYP1: // Apple MacOS PostScript ('typ1') + case OpenTypeFont.TAG_SFNT: // Apple MacOS TrueType ('sfnt') + case OpenTypeFont.TAG_TRUE: // Apple MacOS TrueType ('true') + case OpenTypeFont.TAG_OTTO: // OpenType + return new OpenTypeFont[] { new OpenTypeFont(buf, 0) }; + } + + + /* TrueType Collection, see "TrueType Collections" in + * http://partners.adobe.com/asn/tech/type/opentype/otff.html + */ + if (version == OpenTypeFont.TAG_TTCF) + { + // This code has never been tested. + fonts = new OpenTypeFont[buf.getInt(8)]; + for (int i = 0; i < fonts.length; i++) + fonts[i] = new OpenTypeFont(buf, buf.getInt(16 + 4 * i)); + return fonts; + } + + + /* The MacOS X .dfont format is a Macintosh resource fork in + * a normal file, contaning one or several 'sfnt' resources. + * Unfortunately, MacOS resource forks have no magic code + * that could be used for identification. Instead, we just try + * to extract at least one 'sfnt'. + */ + try + { + MacResourceFork fork = new MacResourceFork(buf); + MacResourceFork.Resource[] rsrc; + + rsrc = fork.getResources(OpenTypeFont.TAG_SFNT); + fonts = new OpenTypeFont[rsrc.length]; + for (int i = 0; i < fonts.length; i++) + fonts[i] = new OpenTypeFont(rsrc[i].getContent(), 0); + + return fonts; + } + catch (Exception ex) + { + } + + throw new FontFormatException("not in OpenType or TrueType format"); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/Scaler.java b/libjava/classpath/gnu/java/awt/font/opentype/Scaler.java new file mode 100644 index 000000000..c7582b666 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/Scaler.java @@ -0,0 +1,205 @@ +/* Scaler.java -- Common superclass for font scalers. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.font.opentype; + +import gnu.java.awt.font.opentype.truetype.Zone; + +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; + + +/** + * An common superclass for all font scalers. The main task of font + * scaler is to retrieve a scaled and hinted outline for a glyph. + * + *

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

Lack of Thread Safety: Font scalers are intentionally + * not safe to access from multiple concurrent + * threads. Synchronization needs to be performed externally. Usually, + * the font that uses this scaler already has obtained a lock before + * calling the scaler. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public abstract class Scaler +{ + /** + * Retrieves the scaled outline of a glyph, adjusting control points + * to the raster grid if necessary. + * + * @param glyph the glyph number whose outline is retrieved. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialias whether or not the rasterizer will perform + * anti-aliasing on the returned path. + * + * @param fractionalMetrics false for adjusting glyph + * positions to the raster grid of device space. + * + * @return the scaled and grid-fitted outline of the specified + * glyph, or null for bitmap fonts. + */ + public abstract GeneralPath getOutline(int glyph, + float pointSize, + AffineTransform transform, + boolean antialias, + boolean fractionalMetrics, + Hinter hinter, int type); + + + /** + * Determines the advance width and height for a glyph. + * + * @param glyphIndex the glyph whose advance width is to be + * determined. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialias true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @param advance a point whose x and y + * fields will hold the advance in each direction. It is well + * possible that both values are non-zero, for example for rotated + * text or for Urdu fonts. + */ + public abstract void getAdvance(int glyphIndex, + float pointSize, + AffineTransform transform, + boolean antialias, + boolean fractionalMetrics, + boolean horizontal, + Point2D advance); + + + /** + * Determines the distance between the base line and the highest + * ascender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialias true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the ascent, which usually is a positive number. + */ + public abstract float getAscent(float pointSize, + AffineTransform transform, + boolean antialias, + boolean fractionalMetrics, + boolean horizontal); + + + /** + * Determines the distance between the base line and the lowest + * descender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialiased true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the descent, which usually is a nagative number. + */ + public abstract float getDescent(float pointSize, + AffineTransform transform, + boolean antialiased, + boolean fractionalMetrics, + boolean horizontal); + + /** + * Returns the raw outline data. This is used for the autofitter atm. + * + * @param glyph the glyph index + * @param transform the transform to apply + * + * @return the raw glyph outline + */ + public abstract Zone getRawOutline(int glyph, AffineTransform transform); +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/Fixed.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Fixed.java new file mode 100644 index 000000000..87dfebd41 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Fixed.java @@ -0,0 +1,176 @@ +/* Fixed.java -- Fixed-point arithmetics for TrueType coordinates. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.font.opentype.truetype; + +import gnu.java.lang.CPStringBuilder; + +/** + * A utility class for fixed-point arithmetics, where numbers are + * represented with 26 dot 6 digits. This representation is used by + * TrueType coordinates. + * + *

A good compiler will inline calls of methods in this class. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public final class Fixed +{ + public static final int ONE = 1<<6; + + + /** + * The constructor is private so nobody can use it. + */ + private Fixed() + { + } + + + /** + * Multiplies two fixed-point numbers. + */ + public static int mul(int a, int b) + { + return (int) ((((long) a) * b) >> 6); + } + + public static int mul16(int a, int b) + { + return (int) ((((long) a) * b) >> 16); + } + + public static int div(int a, int b) + { + return (int) ((((long) a) << 6) / b); + } + + public static int div16(int a, int b) + { + return (int) ((((long) a) << 16) / b); + } + + public static int ceil(int a) + { + return (a + 63) & -64; + } + + + public static int floor(int a) + { + return a & -64; + } + + + /** + * Calculates the length of a fixed-point vector. + */ + public static int vectorLength(int x, int y) + { + int shift; + float fx, fy; + + if (x == 0) + return Math.abs(y); + else if (y == 0) + return Math.abs(x); + + /* Use the FPU. */ + fx = ((float) x) / 64.0f; + fy = ((float) y) / 64.0f; + return (int) (Math.sqrt(fx * fx + fy * fy) * 64.0); + } + + + public static int intValue(int f) + { + return f >> 6; + } + + + public static float floatValue(int f) + { + return ((float) f) / 64; + } + public static float floatValue16(int f) + { + return ((float) f) / 65536; + } + + public static double doubleValue(int f) + { + return ((double) f) / 64; + } + + + public static int valueOf(float f) + { + return (int) (f * 64); + } + + + public static int valueOf(double d) + { + return (int) (d * 64); + } + + public static int valueOf16(double d) + { + return (int) (d * (1 << 16)); + } + + /** + * Makes a string representation of a fixed-point number. + */ + public static String toString(int f) + { + return String.valueOf(floatValue(f)); + } + + + public static String toString(int x, int y) + { + CPStringBuilder sbuf = new CPStringBuilder(40); + sbuf.append('('); + sbuf.append(((float) x) / 64); + sbuf.append(", "); + sbuf.append(((float) y) / 64); + sbuf.append(')'); + return sbuf.toString(); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java new file mode 100644 index 000000000..8a3c56665 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLoader.java @@ -0,0 +1,447 @@ +/* GlyphLoader.java -- Helper for loading TrueType glyph outlines. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.font.opentype.truetype; + +import gnu.java.awt.font.opentype.Hinter; + +import java.awt.geom.AffineTransform; +import java.nio.ByteBuffer; + + +/** + * A class for loading scaled and hinted glyph outlines. + * + *

Lack of Thread Safety: Glyph loaders are intentionally + * not safe to access from multiple concurrent + * threads. Synchronization needs to be performed externally. Usually, + * the font has already obtained a lock before calling the scaler, + * which in turn calls the GlyphLoader. It would thus be wasteful to + * acquire additional locks for the GlyphLoader. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +final class GlyphLoader +{ + /** + * A helper object for locating glyph data. GlyphLocator is an + * abstract superclass, and there is a concretization for each glyph + * location table ('loca') format. + */ + private final GlyphLocator glyphLocator; + + + /** + * A helper object for measuring the advance width and height of a + * glyph. + */ + private final GlyphMeasurer glyphMeasurer; + + + /** + * The virtual machine for executing TrueType bytecodes. + */ + private final VirtualMachine vm; + + + /** + * The number of font units in one em. A typical value is 2048, + * but this depends on the font. + */ + private final int unitsPerEm; + + private final int[] contourEndPoints; + private final byte[] pointFlags; + + + /** + * Constructs a GlyphLoader. + */ + GlyphLoader(GlyphLocator glyphLocator, VirtualMachine vm, + int unitsPerEm, int maxContours, int maxPoints, + GlyphMeasurer glyphMeasurer) + { + this.glyphLocator = glyphLocator; + this.glyphMeasurer = glyphMeasurer; + this.unitsPerEm = unitsPerEm; + this.vm = vm; + + contourEndPoints = new int[maxContours]; + pointFlags = new byte[maxPoints]; + } + + + /** + * @param glyphIndex the number of the glyph whose outlines are to be + * retrieved. + */ + public void loadGlyph(int glyphIndex, + double pointSize, + AffineTransform transform, + boolean antialias, + Zone glyphZone, Hinter hinter) + { + glyphZone.setNumPoints(4); + loadSubGlyph(glyphIndex, pointSize, transform, antialias, glyphZone, + 0, 0, hinter); + } + + public void loadGlyph(int glyphIndex, AffineTransform transform, + Zone glyphZone, Hinter hinter) + { + loadGlyph(glyphIndex, unitsPerEm, transform, false, glyphZone, hinter); + } + + private void loadSubGlyph(int glyphIndex, + double pointSize, + AffineTransform transform, + boolean antialias, + Zone glyphZone, + int preTranslateX, + int preTranslateY, + Hinter hinter) + { + ByteBuffer glyph; + int numContours; + int xMin, yMin, xMax, yMax; + byte flag; + + glyph = glyphLocator.getGlyphData(glyphIndex); + + if (glyph == null) + { + glyphZone.setNumPoints(4); + setPhantomPoints(glyphIndex, 0, glyphZone); + glyphZone.transform(pointSize, transform, unitsPerEm, + preTranslateX, preTranslateY); + return; + } + + numContours = glyph.getShort(); + xMin = glyph.getChar(); + yMin = glyph.getChar(); + xMax = glyph.getChar(); + yMax = glyph.getChar(); + + + if (numContours >= 0) + loadSimpleGlyph(glyphIndex, pointSize, transform, antialias, + numContours, glyph, glyphZone, + preTranslateX, preTranslateY, hinter); + else + loadCompoundGlyph(glyphIndex, pointSize, transform, antialias, + glyph, glyphZone, + preTranslateX, preTranslateY, hinter); + } + + + private void loadSimpleGlyph(int glyphIndex, + double pointSize, AffineTransform transform, + boolean antialias, + int numContours, ByteBuffer glyph, + Zone glyphZone, + int preTranslateX, int preTranslateY, + Hinter hinter) + { + int numPoints; + int posInstructions, numInstructions; + boolean execInstructions; + + execInstructions = vm.setup(pointSize, transform, antialias); + + /* Load the contour end points and determine the number of + * points. + */ + for (int i = 0; i < numContours; i++) + contourEndPoints[i] = glyph.getChar(); + if (numContours > 0) + numPoints = 1 + contourEndPoints[numContours - 1]; + else + numPoints = 0; + glyphZone.setNumPoints(numPoints + 4); + + numInstructions = glyph.getChar(); + posInstructions = glyph.position(); + glyph.position(posInstructions + numInstructions); + loadFlags(numPoints, glyph); + loadCoordinates(numPoints, glyph, glyphZone); + for (int i = 0; i < numContours; i++) + glyphZone.setContourEnd(contourEndPoints[i], true); + + setPhantomPoints(glyphIndex, numPoints, glyphZone); + glyphZone.transform(pointSize, transform, unitsPerEm, + preTranslateX, preTranslateY); + + if (execInstructions && hinter != null) + { + hinter.applyHints(glyphZone); + } + } + + + private static final short ARGS_ARE_WORDS = 1; + private static final short ARGS_ARE_XY_VALUES = 2; + private static final short ROUND_XY_TO_GRID = 4; + private static final short WE_HAVE_A_SCALE = 8; + private static final short MORE_COMPONENTS = 32; + private static final short WE_HAVE_AN_X_AND_Y_SCALE = 64; + private static final short WE_HAVE_A_TWO_BY_TWO = 128; + private static final short WE_HAVE_INSTRUCTIONS = 256; + private static final short USE_MY_METRICS = 512; + private static final short OVERLAP_COMPOUND = 1024; + private static final short SCALED_COMPONENT_OFFSET = 2048; + private static final short UNSCALED_COMPONENT_OFFSET = 4096; + + private void loadCompoundGlyph(int glyphIndex, + double pointSize, + AffineTransform transform, + boolean antialias, + ByteBuffer glyph, + Zone glyphZone, + int preTranslateX, int preTranslateY, + Hinter hinter) + { + short flags; + int subGlyphIndex; + int metricsGlyphIndex; + Zone subGlyphZone = new Zone(glyphZone.getCapacity()); + int arg1, arg2; + double a, b, c, d, e, f; + AffineTransform componentTransform = new AffineTransform(); + + /* By default, use the metrics of the compound glyph. The default + * is overridden if some component glyph has the USE_MY_METRICS + * flag set. + */ + metricsGlyphIndex = glyphIndex; + + do + { + flags = glyph.getShort(); + subGlyphIndex = glyph.getChar(); + + if ((flags & USE_MY_METRICS) != 0) + metricsGlyphIndex = subGlyphIndex; + + if ((flags & ARGS_ARE_WORDS) != 0) + { + arg1 = glyph.getShort(); + arg2 = glyph.getShort(); + } + else + { + arg1 = glyph.get(); + arg2 = glyph.get(); + } + + if ((flags & WE_HAVE_A_SCALE) != 0) + { + a = d = getDouble214(glyph); + b = c = 0.0; + } + else if ((flags & WE_HAVE_AN_X_AND_Y_SCALE) != 0) + { + a = getDouble214(glyph); + d = getDouble214(glyph); + b = c = 0.0; + } + else if ((flags & WE_HAVE_A_TWO_BY_TWO) != 0) + { + a = getDouble214(glyph); + b = getDouble214(glyph); + c = getDouble214(glyph); + d = getDouble214(glyph); + } + else + { + a = d = 1.0; + b = c = 0.0; + } + + double m = Math.max(Math.abs(a), Math.abs(b)); + double n = Math.max(Math.abs(c), Math.abs(d)); + + /* The Apple TrueType specification actually says that m is + * multiplied by two if + * + * abs(abs(a) - abs(c)) <= 33/65536, + * + * but this is probably a typo. On 2003-07-23, Sascha Brawer + * wrote an e-mail message to applefonts@apple.com, asking + * whether this might possibly be an error in the specification. + */ + if (Math.abs(Math.abs(a) - Math.abs(b)) <= 33.0/65536.0) + m = m * 2; + + if (Math.abs(Math.abs(c) - Math.abs(d)) <= 33.0/65536.0) + n = n * 2; + + if ((flags & ARGS_ARE_XY_VALUES) != 0) + { + e = m * arg1; + f = n * arg2; + } + else + e = f = 0.0; + + componentTransform.setTransform(a, b, c, d, 0.0, 0.0); + + // System.out.println("componentTransform = " + componentTransform + // + ", e=" + e + ", f=" + f); + componentTransform.concatenate(transform); + + int pos = glyph.position(); + int lim = glyph.limit(); + + loadSubGlyph(subGlyphIndex, pointSize, componentTransform, + antialias, subGlyphZone, + Math.round((float) e + preTranslateX), + Math.round(-((float) f + preTranslateY)), hinter); + glyphZone.combineWithSubGlyph(subGlyphZone, 4); + glyph.limit(lim).position(pos); + } + while ((flags & MORE_COMPONENTS) != 0); + + setPhantomPoints(metricsGlyphIndex, glyphZone.getSize() - 4, glyphZone); + } + + + private double getDouble214(ByteBuffer buf) + { + return ((double) buf.getShort()) / (1 << 14); + } + + + /** + * Loads the per-point flags of a glyph into the + * pointFlags field. + */ + private void loadFlags(int numPoints, ByteBuffer glyph) + { + byte flag; + int numRepetitions; + + for (int i = 0; i < numPoints; i++) + { + pointFlags[i] = flag = glyph.get(); + if ((flag & 8) != 0) + { + numRepetitions = ((int) glyph.get()) & 0xff; + while (numRepetitions > 0) + { + pointFlags[++i] = flag; + --numRepetitions; + } + } + } + } + + + private void loadCoordinates(int numPoints, ByteBuffer glyph, + Zone glyphZone) + { + int x, y; + byte flag; + + x = 0; + for (int i = 0; i < numPoints; i++) + { + flag = pointFlags[i]; + if ((flag & 2) == 0) + { + if ((flag & 16) == 0) + x += glyph.getShort(); + } + else + { + if ((flag & 16) != 0) + x += (glyph.get() & 0xff); + else + x -= (glyph.get() & 0xff); + } + glyphZone.setOriginalX(i, x); + glyphZone.setOnCurve(i, (flag & 1) == 1); + } + + y = 0; + for (int i = 0; i < numPoints; i++) + { + flag = pointFlags[i]; + if ((flag & 4) == 0) + { + if ((flag & 32) == 0) + y += glyph.getShort(); + } + else + { + if ((flag & 32) != 0) + y += (glyph.get() & 0xff); + else + y -= (glyph.get() & 0xff); + } + glyphZone.setOriginalY(i, -y); + } + } + + + private void setPhantomPoints(int glyphIndex, int numPoints, + Zone glyphZone) + { + /* Phantom point 0: Character origin. */ + glyphZone.setOriginalX(numPoints, 0); + glyphZone.setOriginalY(numPoints, 0); + + /* Phantom point 1: Horizontal advance point. */ + glyphZone.setOriginalX(numPoints + 1, + glyphMeasurer.getAdvanceWidth(glyphIndex, true)); + glyphZone.setOriginalY(numPoints + 1, + glyphMeasurer.getAdvanceHeight(glyphIndex, true)); + + /* Phantom point 2: Vertical origin. */ + int vertX = glyphMeasurer.getAscent(/* vertical */ false); + int vertY = glyphMeasurer.getAscent(/* horizontal */ true); + glyphZone.setOriginalX(numPoints + 2, vertX); + glyphZone.setOriginalY(numPoints + 2, vertY); + + /* Phantom point 3: Vertical advance point. */ + glyphZone.setOriginalX(numPoints + 3, + vertX + glyphMeasurer.getAdvanceWidth(glyphIndex, false)); + glyphZone.setOriginalY(numPoints + 3, + vertY + glyphMeasurer.getAdvanceHeight(glyphIndex, false)); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLocator.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLocator.java new file mode 100644 index 000000000..fc2256b15 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphLocator.java @@ -0,0 +1,187 @@ +/* GlyphLocator.java -- Locates outlines of TrueType glyphs. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.font.opentype.truetype; + +import java.awt.FontFormatException; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.IntBuffer; + + +/** + * Locates glyph outlines in a TrueType or OpenType glyf + * table. + * + * @see Adobe’s specification of the OpenType ‘loca’ + * table + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +abstract class GlyphLocator +{ + /** + * The actual glyph data of the font, which is contained in the + * 'glyf' table. + */ + protected ByteBuffer glyfTable; + + + /** + * Creates a new GlyphLocator for a loca table. + * + * @param format the format of the loca table. The + * value must be 0 for two-byte offsets, or 1 for four-byte + * offsets. TrueType and OpenType fonts indicate the format in the + * indexToLoc field of the font header. + * + * @param loca the loca table of the font, which + * contains the position of each glyph in the glyf + * table. + * + * @param glyf the glyf table of the font, which + * contains the outline data of each glyph. + * + * @throws FontFormatException if format is neither 0 + * nor 1. + */ + public static GlyphLocator forTable(int format, ByteBuffer loca, + ByteBuffer glyf) + throws FontFormatException + { + switch (format) + { + case 0: + return new GlyphLocator.TwoByte(loca, glyf); + + case 1: + return new GlyphLocator.FourByte(loca, glyf); + + default: + throw new FontFormatException("unsupported loca format"); + } + } + + + /** + * Locates the outline data for a glyph. + * + *

For efficiency, the glyph locator does not create a new buffer + * for each invocation. Instead, this method always returns the same + * buffer object. Therefore, the data of a glyph must have been read + * completely before another glyph of the same font gets requested + * through this method. + * + * @param glyph the number of the glyph whose outlines are to be + * retrieved. + * + * @return a buffer whose position is set to the first byte of glyph + * data, and whose limit is set to disallow accessing any data that + * does not belong to the glyph. If there is no outline data for the + * requested glyph, as would be the case for the space glyph, the + * result will be null. + */ + public abstract ByteBuffer getGlyphData(int glyph); + + + /** + * A GlyphLocator that locates glyphs using two-byte offsets, + * interpreting loca tables of format 0. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + private final static class TwoByte + extends GlyphLocator + { + final CharBuffer indexToLoc; + + TwoByte(ByteBuffer loca, ByteBuffer glyf) + { + this.glyfTable = glyf; + indexToLoc = loca.asCharBuffer(); + } + + + public ByteBuffer getGlyphData(int glyph) + { + int offset, limit; + offset = ((int) indexToLoc.get(glyph)) << 1; + limit = ((int) indexToLoc.get(glyph + 1)) << 1; + if (offset >= limit) + return null; + + glyfTable.limit(limit).position(offset); + return glyfTable; + } + } + + + /** + * A GlyphLocator that locates glyphs using four-byte offsets, + * interpreting loca tables of format 1. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ + private final static class FourByte + extends GlyphLocator + { + final IntBuffer indexToLoc; + + FourByte(ByteBuffer loca, ByteBuffer glyf) + { + this.glyfTable = glyf; + indexToLoc = loca.asIntBuffer(); + } + + + public ByteBuffer getGlyphData(int glyph) + { + int offset, limit; + offset = indexToLoc.get(glyph); + limit = indexToLoc.get(glyph + 1); + if (offset >= limit) + return null; + + glyfTable.limit(limit).position(offset); + return glyfTable; + } + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphMeasurer.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphMeasurer.java new file mode 100644 index 000000000..452456d13 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/GlyphMeasurer.java @@ -0,0 +1,228 @@ +/* GlyphMeasurer.java -- Helper for measuring TrueType glyphs. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.font.opentype.truetype; + +import java.awt.FontFormatException; +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; + + +/** + * A class for measuring TrueType and OpenType glyphs. + * + *

Lack of Thread Safety: Glyph measurers are intentionally + * not safe to access from multiple concurrent + * threads. Synchronization needs to be performed externally. Usually, + * the font has already obtained a lock before calling the scaler, + * which in turn calls the GlyphMeasurer. It would thus be wasteful to + * acquire additional locks for the GlyphMeasurer. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +final class GlyphMeasurer +{ + /** + * A view buffer that allows accessing the contents of the + * font’s hmtx table as shorts. + */ + private final ShortBuffer horizontalGlyphMetrics; + + + /** + * A view buffer that allows accessing the contents of the + * font’s vmtx table as shorts. + */ + private final ShortBuffer verticalGlyphMetrics; + + + private final int numLongHorizontalMetricsEntries; + private final int numLongVerticalMetricsEntries; + + private final int horizontalAscent; + private final int verticalAscent; + + private final int horizontalDescent; + private final int verticalDescent; + + private final int horizontalLineGap; + + + /** + * Constructs a GlyphMeasurer from TrueType/OpenType font tables. + * + * @param hhea the hhea table, which contains + * information about horizontal metrics that is common to all + * glyphs. + * + * @param hmtx the hmtx table, which contains + * glyph-specific information about horizontal metrics. + * + * @param vhea the vhea table, which contains + * information about vertical metrics that is common to all + * glyphs. If a font does not provide such a table, pass + * null. + * + * @param vmtx the vmtx table, which contains + * glyph-specific information about vertical metrics. If a font + * does not provide such a table, pass null. + */ + GlyphMeasurer(ByteBuffer hhea, ByteBuffer hmtx, + ByteBuffer vhea, ByteBuffer vmtx) + throws FontFormatException + { + if ((hhea.getInt(0) != 0x00010000) || (hhea.getInt(30) != 0)) + throw new FontFormatException("unsupported hhea format"); + + horizontalAscent = hhea.getShort(4); + horizontalDescent = hhea.getShort(6); + horizontalLineGap = hhea.getShort(8); + + numLongHorizontalMetricsEntries = hhea.getChar(34); + horizontalGlyphMetrics = hmtx.asShortBuffer(); + + if (vhea != null) + { + verticalAscent = vhea.getShort(4); + verticalDescent = vhea.getShort(6); + numLongVerticalMetricsEntries = vhea.getChar(34); + verticalGlyphMetrics = vmtx.asShortBuffer(); + } + else + { + verticalAscent = /* advanceWidthMax */ hhea.getChar(10) / 2; + verticalDescent = -verticalAscent; + numLongVerticalMetricsEntries = 0; + verticalGlyphMetrics = null; + } + } + + + /** + * Returns the distance from the baseline to the highest ascender. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the maximal ascent, in font units. + */ + public int getAscent(boolean horizontal) + { + return horizontal ? horizontalAscent : verticalAscent; + } + + + /** + * Returns the distance from the baseline to the lowest descender. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the maximal descent, in font units. + */ + public int getDescent(boolean horizontal) + { + return horizontal ? horizontalDescent : verticalDescent; + } + + + /** + * Returns the typographic line gap. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the line gap, in font units. + */ + public int getLineGap(boolean horizontal) + { + return horizontalLineGap; + } + + + /** + * Determines the advance width of a glyph, without considering + * hinting. + * + * @param glyphIndex the index of the glyph whose advance width is + * to be determined. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the advance width, in font units. + */ + public int getAdvanceWidth(int glyphIndex, boolean horizontal) + { + if (!horizontal) + return 0; + + glyphIndex = Math.min(glyphIndex, + numLongHorizontalMetricsEntries - 1); + return horizontalGlyphMetrics.get(glyphIndex << 1); + } + + + /** + * Determines the advance width of a glyph, without considering + * hinting. + * + * @param glyphIndex the index of the glyph whose advance width is + * to be determined. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the advance width, in font units. + */ + public int getAdvanceHeight(int glyphIndex, boolean horizontal) + { + if (horizontal) + return 0; + + /* If a font does not provide vertical glyph metrics, advance + * by the height of one horizontal line. + */ + if (verticalGlyphMetrics == null) + return horizontalAscent - horizontalDescent + horizontalLineGap; + + glyphIndex = Math.min(glyphIndex, + numLongVerticalMetricsEntries - 1); + return verticalGlyphMetrics.get(glyphIndex << 1); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/Point.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Point.java new file mode 100644 index 000000000..438eb6558 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/Point.java @@ -0,0 +1,287 @@ +/* Point.java -- Holds information for one point on a glyph outline + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.font.opentype.truetype; + +import gnu.java.lang.CPStringBuilder; + +/** + * Encapsulates information regarding one point on a glyph outline. + */ +public class Point +{ + public static final short FLAG_TOUCHED_X = 1; + public static final short FLAG_TOUCHED_Y = 2; + public static final short FLAG_ON_CURVE = 4; + public static final short FLAG_CONTOUR_END = 8; + public static final short FLAG_WEAK_INTERPOLATION = 16; + public static final short FLAG_INFLECTION = 32; + public static final short FLAG_DONE_X = 64; + public static final short FLAG_DONE_Y = 128; + + /** + * Right direction. + */ + public static final int DIR_RIGHT = 1; + + /** + * Left direction. + */ + public static final int DIR_LEFT = -1; + + /** + * Up direction. + */ + public static final int DIR_UP = 2; + + /** + * Down direction. + */ + public static final int DIR_DOWN = -2; + + /** + * The original x coordinate in font units. + */ + int origX; + + /** + * The original y coordinate in font units. + */ + int origY; + + /** + * The x coordinate scaled to the target. + */ + int scaledX; + + /** + * The y coordinate scaled to the target. + */ + int scaledY; + + /** + * The final hinted and scaled x coordinate. + */ + int x; + + /** + * The final hinted and scaled y coordinate. + */ + int y; + + int u; + int v; + + /** + * The glyph flags. + */ + short flags; + + /** + * The previous point in the contour. + */ + private Point prev; + + /** + * The next point in the contour. + */ + private Point next; + + /** + * The in-direction of the point, according to the DIR_* constants of this + * class. + */ + int inDir; + + /** + * The out-direction of the point, according to the DIR_* constants of this + * class. + */ + int outDir; + + public Point getNext() + { + return next; + } + + public void setNext(Point next) + { + this.next = next; + } + + public Point getPrev() + { + return prev; + } + + public void setPrev(Point prev) + { + this.prev = prev; + } + + public int getOrigX() + { + return origX; + } + + public void setOrigX(int origX) + { + this.origX = origX; + } + + public int getOrigY() + { + return origY; + } + + public void setOrigY(int origY) + { + this.origY = origY; + } + + public int getInDir() + { + return inDir; + } + + public void setInDir(int inDir) + { + this.inDir = inDir; + } + + public int getOutDir() + { + return outDir; + } + + public void setOutDir(int outDir) + { + this.outDir = outDir; + } + + public short getFlags() + { + return flags; + } + + public void setFlags(short flags) + { + this.flags = flags; + } + + public void addFlags(short flags) + { + this.flags |= flags; + } + + public boolean isControlPoint() + { + return (flags & FLAG_ON_CURVE) == 0; + } + + public int getU() + { + return u; + } + + public void setU(int u) + { + this.u = u; + } + + public int getV() + { + return v; + } + + public void setV(int v) + { + this.v = v; + } + + public String toString() + { + CPStringBuilder s = new CPStringBuilder(); + s.append("[Point] origX: "); + s.append(origX); + s.append(", origY: "); + s.append(origY); + // TODO: Add more info when needed. + return s.toString(); + } + + public int getX() + { + return x; + } + + public void setX(int x) + { + this.x = x; + } + + public int getY() + { + return y; + } + + public void setY(int y) + { + this.y = y; + } + + public int getScaledX() + { + return scaledX; + } + + public void setScaledX(int scaledX) + { + this.scaledX = scaledX; + } + + public int getScaledY() + { + return scaledY; + } + + public void setScaledY(int scaledY) + { + this.scaledY = scaledY; + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java new file mode 100644 index 000000000..1d5c53f9d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/TrueTypeScaler.java @@ -0,0 +1,380 @@ +/* TrueTypeScaler.java -- Font scaler for TrueType outlines. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.font.opentype.truetype; + +import gnu.java.awt.font.opentype.Hinter; +import gnu.java.awt.font.opentype.Scaler; + +import java.awt.FontFormatException; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.nio.ByteBuffer; + + +/** + * A scaler for fonts whose outlines are described in the TrueType + * format. + * + *

Lack of Thread Safety: Font scalers are intentionally + * not safe to access from multiple concurrent threads. + * Synchronization needs to be performed externally. Usually, the font + * that uses this scaler already has obtained a lock before calling + * the scaler. + * + * @author Sascha Brawer (brawer@dandelis.ch) + */ +public final class TrueTypeScaler + extends Scaler +{ + /** + * The TrueType or OpenType table that contains the glyph outlines. + */ + private ByteBuffer glyfTable; + + + /** + * A helper object for loading glyph outlines. + */ + private GlyphLoader glyphLoader; + + + /** + * A helper object for measuring the advance width and height of a + * glyph. + */ + private final GlyphMeasurer glyphMeasurer; + + private final Zone glyphZone; + + + /** + * The number of units per em. A typical value is 2048, but some + * font use other numbers as well. + */ + private int unitsPerEm; + + + /** + * Constructs a new TrueTypeScaler. + * + * @param unitsPerEm the number of font units per em. This value can + * be retrieved from the font’s head table. + * + * @param maxp the maxp table of the font, which + * contains various constants needed for setting up the virtual + * machine that interprets TrueType bytecodes. + * + * @param controlValueTable the cvt table of the font, + * which contains the initial values of the control value table. + * + * @param fpgm the fpgm table of the font, which + * contains a font program that is executed exactly once. The + * purpose of the font program is to define functions and to patch + * the interpreter. + * + * @param locaFormat the format of the loca table. The + * value must be 0 for two-byte offsets, or 1 for four-byte + * offsets. TrueType and OpenType fonts indicate the format in the + * indexToLoc field of the font header. + * + * @param loca the loca table of the font, which + * contains for each glyph the offset of its outline data + * in glyf. + * + * @param glyf the glyf table of the font, which + * contains the outline data for all glyphs in the font. + * + * @param preProgram the prep table of the font, which + * contains a program that is executed whenever the point size or + * the device transform have changed. This program is called + * pre-program because it gets executed before the instructions of + * the individual glyphs. If the font does not contain a + * pre-program, pass null. + * + * @throws FontFormatException if format is neither 0 + * nor 1. + */ + public TrueTypeScaler(int unitsPerEm, + ByteBuffer hhea, + ByteBuffer htmx, + ByteBuffer vhea, + ByteBuffer vtmx, + ByteBuffer maxp, + ByteBuffer controlValueTable, + ByteBuffer fpgm, + int locaFormat, ByteBuffer loca, + ByteBuffer glyf, + ByteBuffer preProgram) + throws FontFormatException + { + int maxContours, maxPoints; + VirtualMachine vm; + + maxContours = Math.max(/* maxContours */ (int) maxp.getChar(8), + /* maxCompositeContours */ (int) maxp.getChar(12)) + + /* fix for some broken fonts */ 8; + maxPoints = Math.max(/* maxPoints */ (int) maxp.getChar(6), + /* maxCompositePoints */ (int) maxp.getChar(10)) + + /* fix for some broken fonts */ 12; + + + glyphZone = new Zone(maxPoints + /* four phantom points */ 4); + this.glyfTable = glyf; + vm = new VirtualMachine(unitsPerEm, maxp, + controlValueTable, fpgm, + preProgram); + + GlyphLocator locator = GlyphLocator.forTable(locaFormat, loca, glyf); + glyphMeasurer = new GlyphMeasurer(hhea, htmx, vhea, vtmx); + glyphLoader = new GlyphLoader(locator, vm, unitsPerEm, + maxContours, maxPoints, + glyphMeasurer); + + this.unitsPerEm = unitsPerEm; + } + + + /** + * Retrieves the scaled outline of a glyph, adjusting control points + * to the raster grid if necessary. + * + * @param glyphIndex the glyph number whose outline is retrieved. + * + * @param pointSize the point size for the glyph. + * + * @param deviceTransform an affine transformation for the device. + * + * @param antialias whether or not the rasterizer will perform + * anti-aliasing on the returned path. + * + * @param fractionalMetrics false for adjusting glyph + * positions to the raster grid of device space. + */ + public GeneralPath getOutline(int glyphIndex, + float pointSize, + AffineTransform deviceTransform, + boolean antialias, + boolean fractionalMetrics, Hinter hinter, + int type) + { + glyphLoader.loadGlyph(glyphIndex, pointSize, deviceTransform, + antialias, glyphZone, hinter); + return glyphZone.getPath(type); + } + + public Zone getRawOutline(int glyphIndex, AffineTransform transform) + { + Zone zone = new Zone(glyphZone.getCapacity()); + glyphLoader.loadGlyph(glyphIndex, transform, zone, null); + return zone; + } + + /** + * Determines the advance width and height for a glyph. + * + * @param glyphIndex the glyph whose advance width and height is to + * be determined. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialias true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @param advance a point whose x and y + * fields will hold the advance in each direction. It is possible + * that both values are non-zero, for example if + * transform is a rotation, or in the case of Urdu + * fonts. + */ + public void getAdvance(int glyphIndex, + float pointSize, + AffineTransform transform, + boolean antialias, + boolean fractionalMetrics, + boolean horizontal, + Point2D advance) + { + double x, y; + double scaleFactor = (double) pointSize / unitsPerEm; + + /* FIXME: Should grid-fit if needed. Also, use cache if present + * in the font. + */ + advance.setLocation( + scaleFactor * glyphMeasurer.getAdvanceWidth(glyphIndex, horizontal), + scaleFactor * glyphMeasurer.getAdvanceHeight(glyphIndex, horizontal)); + + transform.transform(advance, advance); + } + + + /** + * Scales a value from font units to pixels, given the point size + * and the transform. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. + * + * @param fractionalMetrics true for fractional + * metrics, false for rounding the result to a pixel + * boundary. + * + * @param horizontal true if the funits + * value is along the x axis, false if it is along the + * y axis. + */ + private float scaleFromFUnits(int funits, + float pointSize, + AffineTransform transform, + boolean fractionalMetrics, + boolean horizontal) + { + double s; + + s = (double) pointSize / unitsPerEm; + if (transform != null) + s *= horizontal ? transform.getScaleY() : transform.getScaleX(); + s *= funits; + if (!fractionalMetrics) + s = Math.round(s); + return (float) s; + } + + + /** + * Determines the distance between the base line and the highest + * ascender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialias true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the ascent, which usually is a positive number. + */ + public float getAscent(float pointSize, + AffineTransform transform, + boolean antialias, + boolean fractionalMetrics, + boolean horizontal) + { + /* Note that the ascent is orthogonal to the direction of line + * layout: If the line direction is horizontal, the measurement of + * ascent is along the vertical axis, and vice versa. + */ + return scaleFromFUnits(glyphMeasurer.getAscent(horizontal), + pointSize, + transform, + fractionalMetrics, + /* reverse */ !horizontal); + } + + + /** + * Determines the distance between the base line and the lowest + * descender. + * + * @param pointSize the point size of the font. + * + * @param transform a transform that is applied in addition to + * scaling to the specified point size. This is often used for + * scaling according to the device resolution. Those who lack any + * aesthetic sense may also use the transform to slant or stretch + * glyphs. + * + * @param antialiased true for anti-aliased rendering, + * false for normal rendering. For hinted fonts, + * this parameter may indeed affect the result. + * + * @param fractionalMetrics true for fractional metrics, + * false for rounding the result to a pixel boundary. + * + * @param horizontal true for horizontal line layout, + * false for vertical line layout. + * + * @return the descent, which usually is a nagative number. + */ + public float getDescent(float pointSize, + AffineTransform transform, + boolean antialiased, + boolean fractionalMetrics, + boolean horizontal) + { + /* Note that the descent is orthogonal to the direction of line + * layout: If the line direction is horizontal, the measurement of + * descent is along the vertical axis, and vice versa. + */ + return scaleFromFUnits(glyphMeasurer.getDescent(horizontal), + pointSize, + transform, + fractionalMetrics, + /* reverse */ !horizontal); + } +} diff --git a/libjava/classpath/gnu/java/awt/font/opentype/truetype/VirtualMachine.java b/libjava/classpath/gnu/java/awt/font/opentype/truetype/VirtualMachine.java new file mode 100644 index 000000000..512c39ffd --- /dev/null +++ b/libjava/classpath/gnu/java/awt/font/opentype/truetype/VirtualMachine.java @@ -0,0 +1,1815 @@ +/* VirtualMachine.java -- Virtual machine for TrueType bytecodes. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.font.opentype.truetype; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.FontFormatException; +import java.awt.geom.AffineTransform; +import java.nio.ByteBuffer; +import java.nio.ShortBuffer; + + +/** + * A virtual machine for interpreting TrueType bytecodes. + * + *

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

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

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

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

+ * + *

The relevant patents are listed subsequently.

+ * + *

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

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

An example curve

+ * + *

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

+ * + *

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

+ * + *

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

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

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

+ * + *

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

+ * + *

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

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

+ + + diff --git a/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java b/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java new file mode 100644 index 000000000..1334866f2 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/java2d/AbstractGraphics2D.java @@ -0,0 +1,2094 @@ +/* AbstractGraphics2D.java -- Abstract Graphics2D implementation + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.java2d; + +import gnu.java.util.LRUCache; + +import java.awt.AWTError; +import java.awt.AlphaComposite; +import java.awt.AWTPermission; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.CompositeContext; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Paint; +import java.awt.PaintContext; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.Toolkit; +import java.awt.RenderingHints.Key; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.FilteredImageSource; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.ReplicateScaleFilter; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.awt.image.renderable.RenderableImage; +import java.text.AttributedCharacterIterator; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.Map; +import java.util.WeakHashMap; + +/** + * This is a 100% Java implementation of the Java2D rendering pipeline. It is + * meant as a base class for Graphics2D implementations. + * + *

Backend interface

+ *

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

+ *

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

+ *

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

+ *

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

+ * + *

Acceleration options

+ *

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

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

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

+ + + diff --git a/libjava/classpath/gnu/java/awt/peer/ClasspathDesktopPeer.java b/libjava/classpath/gnu/java/awt/peer/ClasspathDesktopPeer.java new file mode 100644 index 000000000..fd4f498aa --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/ClasspathDesktopPeer.java @@ -0,0 +1,301 @@ +/* ClasspathDesktopPeer.java -- Offers a concrete implementation for DesktopPeer + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + +package gnu.java.awt.peer; + +import java.awt.AWTPermission; +import java.awt.Desktop.Action; +import java.awt.peer.DesktopPeer; + +import java.io.File; +import java.io.IOException; + +import java.net.URI; + +import java.util.prefs.Preferences; + +/** + * Offers a common implementation for the Desktop peers, that enables + * access to default system application within java processes. + * + * @author Mario Torre + */ +public class ClasspathDesktopPeer + implements DesktopPeer +{ + /** This is the fallback browser, if no desktop was detected. */ + protected static final String _DEFAULT_BROWSER = "firefox"; + + /** gnu.java.awt.peer.Desktop.html.command */ + protected static final String _BROWSE = "html"; + + /** gnu.java.awt.peer.Desktop.mail.command */ + protected static final String _MAIL = "mail"; + + /** gnu.java.awt.peer.Desktop.edit.command */ + protected static final String _EDIT = "edit"; + + /** gnu.java.awt.peer.Desktop.print.command */ + protected static final String _PRINT = "print"; + + /** gnu.java.awt.peer.Desktop.open.command */ + protected static final String _OPEN = "open"; + + /** */ + protected static final KDEDesktopPeer kde = new KDEDesktopPeer(); + + /** */ + protected static final GnomeDesktopPeer gnome = new GnomeDesktopPeer(); + + /** */ + protected static final ClasspathDesktopPeer classpath = + new ClasspathDesktopPeer(); + + /** + * Preference subsystem. Packagers and users can override the default + * behaviour of this class via preferences and system properties. + */ + protected Preferences prefs = + Preferences.userNodeForPackage(ClasspathDesktopPeer.class).node("Desktop"); + + /** + * @param target + */ + protected ClasspathDesktopPeer() + { + /* nothing to do */ + } + + public boolean isSupported(Action action) + { + String check = null; + + switch(action) + { + case BROWSE: + check = _BROWSE; + break; + + case MAIL: + check = _MAIL; + break; + + case EDIT: + check = _EDIT; + break; + + case PRINT: + check = _PRINT; + break; + + case OPEN: default: + check = _OPEN; + break; + } + + return this.supportCommand(check); + } + + public void browse(URI url) throws IOException + { + checkPermissions(); + + String browser = getCommand(_BROWSE); + + if (browser == null) + throw new UnsupportedOperationException(); + + browser = browser + " " + url.toString(); + + Runtime.getRuntime().exec(browser); + } + + public void edit(File file) throws IOException + { + checkPermissions(file, false); + + String edit = getCommand(_EDIT); + + if (edit == null) + throw new UnsupportedOperationException(); + + edit = edit + " " + file.getAbsolutePath(); + Runtime.getRuntime().exec(edit); + } + + public void mail(URI mailtoURL) throws IOException + { + checkPermissions(); + + String scheme = mailtoURL.getScheme(); + if (scheme == null || !scheme.equalsIgnoreCase("mailto")) + throw new IllegalArgumentException("URI Scheme not of type mailto"); + + String mail = getCommand(_MAIL); + + if (mail == null) + throw new UnsupportedOperationException(); + + mail = mail + " " + mailtoURL.toString(); + + Runtime.getRuntime().exec(mail); + } + + public void mail() throws IOException + { + checkPermissions(); + + String mail = getCommand(_MAIL); + + if (mail == null) + throw new UnsupportedOperationException(); + + Runtime.getRuntime().exec(mail); + } + + public void open(File file) throws IOException + { + checkPermissions(file, true); + + String open = getCommand(_OPEN); + + if (open == null) + throw new UnsupportedOperationException(); + + open = open + " " + file.getAbsolutePath(); + Runtime.getRuntime().exec(open); + } + + public void print(File file) throws IOException + { + checkPrintPermissions(file); + + String print = getCommand(_PRINT); + + if (print == null) + throw new UnsupportedOperationException(); + + print = print + " " + file.getAbsolutePath(); + Runtime.getRuntime().exec(print); + } + + protected String getCommand(String action) + { + // check if a system property exist + String command = + System.getProperty("gnu.java.awt.peer.Desktop." + action + ".command"); + + // otherwise, get it from preferences, if any + if (command == null) + { + command = prefs.node(action).get("command", null); + } + + return command; + } + + /** + * Note: Checks for AWTPermission("showWindowWithoutWarningBanner") only. + */ + protected void checkPermissions() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPermission(new AWTPermission("showWindowWithoutWarningBanner")); + } + } + + /** + * Calls checkPermissions() and checks for SecurityManager.checkRead() + * and, if readOnly is false, for SecurityManager.checkWrite() + */ + protected void checkPermissions(File file, boolean readOnly) + { + checkPermissions(); + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkRead(file.toString()); + if (!readOnly) sm.checkWrite(file.toString()); + } + } + + /** + * Calls checkPermissions(file, true) and checks for + * SecurityManager.checkPrintJobAccess() + */ + protected void checkPrintPermissions(File file) + { + checkPermissions(file, true); + + SecurityManager sm = System.getSecurityManager(); + if (sm != null) { + sm.checkPrintJobAccess(); + } + } + + /** + * @param check + * @return + */ + protected boolean supportCommand(String check) + { + return ((this.getCommand(check) != null) ? true : false); + } + + /** + * @return + */ + public static DesktopPeer getDesktop() + { + // check if we are under Gnome or KDE or anything else + String desktopSession = System.getenv("GNOME_DESKTOP_SESSION_ID"); + if (desktopSession == null) + { + desktopSession = System.getenv("KDE_FULL_SESSION"); + if (desktopSession != null) + return kde; + } + else + { + return gnome; + } + + // revert to this class for default values + return classpath; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java b/libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java new file mode 100644 index 000000000..96677a4af --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/ClasspathFontPeer.java @@ -0,0 +1,865 @@ +/* ClasspathFontPeer.java -- Font peer used by GNU Classpath. + Copyright (C) 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer; + +import gnu.java.awt.ClasspathToolkit; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Toolkit; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineMetrics; +import java.awt.font.TextAttribute; +import java.awt.font.TransformAttribute; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.peer.FontPeer; +import java.text.AttributedCharacterIterator; +import java.text.CharacterIterator; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Locale; +import java.util.Map; + +/** + * A peer for fonts that are used inside Classpath. The purpose of + * this interface is to abstract from platform-specific font handling + * in the Classpath implementation of java.awt.Font and related + * classes. + * + *

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

+ * + *

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

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

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

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

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

+ * + *

This situation would occur for an OpenType or TrueType font + * that has a post table of format 3 and provides a + * mapping from glyph IDs to Unicode sequences through a + * Zapf table. If the same sequence of Unicode + * codepoints leads to different glyphs (depending on contextual + * position, for example, or on typographic sophistication level), + * the same name would get synthesized for those glyphs. To avoid + * this, the font peer would have to go through the names of all + * glyphs, which would make this operation very inefficient with + * large fonts. + * + * @param font the font containing the glyph whose name is + * requested. + * + * @param glyphIndex the glyph whose name the caller wants to + * retrieve. + * + * @return the glyph name, or null if a font does not + * provide glyph names. + */ + + public abstract String getGlyphName (Font font, int glyphIndex); + + + /** + * Implementation of {@link + * Font#createGlyphVector(FontRenderContext, String)}, {@link + * Font#createGlyphVector(FontRenderContext, char[])}, and {@link + * Font#createGlyphVector(FontRenderContext, CharacterIterator)}. + * + * @param font the font object that the created GlyphVector will return + * when it gets asked for its font. This argument is needed because the + * public API of {@link GlyphVector} works with {@link java.awt.Font}, + * not with font peers. + */ + + public abstract GlyphVector createGlyphVector (Font font, + FontRenderContext frc, + CharacterIterator ci); + + + /** + * Implementation of {@link Font#createGlyphVector(FontRenderContext, + * int[])}. + * + * @param font the font object that the created GlyphVector will return + * when it gets asked for its font. This argument is needed because the + * public API of {@link GlyphVector} works with {@link java.awt.Font}, + * not with font peers. + */ + + public abstract GlyphVector createGlyphVector (Font font, + FontRenderContext ctx, + int[] glyphCodes); + + + /** + * Implementation of {@link Font#layoutGlyphVector(FontRenderContext, + * char[], int, int, int)}. + * + * @param font the font object that the created GlyphVector will return + * when it gets asked for its font. This argument is needed because the + * public API of {@link GlyphVector} works with {@link java.awt.Font}, + * not with font peers. + */ + + public abstract GlyphVector layoutGlyphVector (Font font, + FontRenderContext frc, + char[] chars, int start, + int limit, int flags); + + + /** + * Implementation of {@link Font#getFontMetrics()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public abstract FontMetrics getFontMetrics (Font font); + + + /** + * Implementation of {@link Font#hasUniformLineMetrics()} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public abstract boolean hasUniformLineMetrics (Font font); + + + /** + * Implementation of {@link Font#getLineMetrics(CharacterIterator, int, + * int, FontRenderContext)} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public abstract LineMetrics getLineMetrics (Font font, + CharacterIterator ci, + int begin, int limit, + FontRenderContext rc); + + /** + * Implementation of {@link Font#getMaxCharBounds(FontRenderContext)} + * + * @param font the font this peer is being called from. This may be + * useful if you are sharing peers between Font objects. Otherwise it may + * be ignored. + */ + + public abstract Rectangle2D getMaxCharBounds (Font font, + FontRenderContext rc); + +} diff --git a/libjava/classpath/gnu/java/awt/peer/EmbeddedWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/EmbeddedWindowPeer.java new file mode 100644 index 000000000..4c64a1d2d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/EmbeddedWindowPeer.java @@ -0,0 +1,47 @@ +/* EmbeddedWindowPeer.java -- Interface for window peers that may be + embedded into other applications + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer; + +import java.awt.peer.FramePeer; + +public interface EmbeddedWindowPeer extends FramePeer +{ + void embed (long handle); +} diff --git a/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java b/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java new file mode 100644 index 000000000..fe128c26c --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/GLightweightPeer.java @@ -0,0 +1,461 @@ +/* GLightweightPeer.java -- + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer; + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.BufferCapabilities; +import java.awt.Color; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.event.PaintEvent; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.VolatileImage; +import java.awt.peer.ContainerPeer; +import java.awt.peer.LightweightPeer; + +/** + * A stub class that implements the ComponentPeer and ContainerPeer + * interfaces using callbacks into the Component and Container + * classes. GLightweightPeer allows the Component and Container + * classes to treat lightweight and heavyweight peers in the same way. + * + * Lightweight components are painted directly onto their parent + * containers through an Image object provided by the toolkit. + */ +public class GLightweightPeer + implements LightweightPeer, ContainerPeer +{ + public GLightweightPeer() + { + // Nothing to do here. + } + + // -------- java.awt.peer.ContainerPeer implementation: + + public Insets insets() + { + // Nothing to do here for lightweights. + return null; + } + + public Insets getInsets() + { + // Nothing to do here for lightweights. + return null; + } + + public void beginValidate() + { + // Nothing to do here for lightweights. + } + + public void endValidate() + { + // Nothing to do here for lightweights. + } + + public void beginLayout() + { + // Nothing to do here for lightweights. + } + + public void endLayout() + { + // Nothing to do here for lightweights. + } + + public boolean isPaintPending() + { + // Nothing to do here for lightweights. + return false; + } + + // -------- java.awt.peer.ComponentPeer implementation: + + public int checkImage(Image img, int width, int height, ImageObserver o) + { + // Nothing to do here for lightweights. + return -1; + } + + public Image createImage(ImageProducer prod) + { + // Nothing to do here for lightweights. + return null; + } + + /* This method is not called. */ + public Image createImage(int width, int height) + { + // Nothing to do here for lightweights. + return null; + } + + public void disable() + { + // Nothing to do here for lightweights. + } + + public void dispose() + { + // Nothing to do here for lightweights. + } + + public void enable() + { + // Nothing to do here for lightweights. + } + + public GraphicsConfiguration getGraphicsConfiguration() + { + // Nothing to do here for lightweights. + return null; + } + + public FontMetrics getFontMetrics(Font f) + { + // We shouldn't end up here, but if we do we can still try do something + // reasonable. + Toolkit tk = Toolkit.getDefaultToolkit(); + return tk.getFontMetrics(f); + } + + /* Returning null here tells the Component object that called us to + * use its parent's Graphics. */ + public Graphics getGraphics() + { + // Nothing to do here for lightweights. + return null; + } + + public Point getLocationOnScreen() + { + // Nothing to do here for lightweights. + return null; + } + + public Dimension getMinimumSize() + { + return minimumSize(); + } + + public Dimension getPreferredSize() + { + return preferredSize(); + } + + /* Returning null here tells the Component object that called us to + * use its parent's Toolkit. */ + public Toolkit getToolkit() + { + // Nothing to do here for lightweights. + return null; + } + + public void handleEvent(AWTEvent e) + { + // This can only happen when an application posts a PaintEvent for + // a lightweight component directly. We still support painting for + // this case. + if (e instanceof PaintEvent) + { + PaintEvent pe = (PaintEvent) e; + Component target = (Component) e.getSource(); + if (target != null && target.isShowing()) + { + Graphics g = target.getGraphics(); + if (g != null) + { + try + { + Rectangle clip = pe.getUpdateRect(); + g.setClip(clip); + target.paint(g); + } + finally + { + g.dispose(); + } + } + } + } + } + + public void hide() + { + // Nothing to do here for lightweights. + } + + public boolean isFocusable() + { + // Nothing to do here for lightweights. + return false; + } + + public boolean isFocusTraversable() + { + // Nothing to do here for lightweights. + return false; + } + + public Dimension minimumSize() + { + return new Dimension(0, 0); + } + + public Dimension preferredSize() + { + return new Dimension(0, 0); + } + + public void paint(Graphics graphics) + { + // Nothing to do here for lightweights. + } + + public boolean prepareImage(Image img, int width, int height, + ImageObserver o) + { + // Nothing to do here for lightweights. + return false; + } + + public void print(Graphics graphics) + { + // Nothing to do here for lightweights. + } + + public void repaint(long tm, int x, int y, int width, int height) + { + // Nothing to do here for lightweights. + } + + public void requestFocus() + { + // Nothing to do here for lightweights. + } + + public boolean requestFocus(Component source, boolean bool1, boolean bool2, + long x) + { + // Nothing to do here for lightweights. + return false; + } + + public void reshape(int x, int y, int width, int height) + { + // Nothing to do here for lightweights. + } + + public void setBackground(Color color) + { + // Nothing to do here for lightweights. + } + + public void setBounds(int x, int y, int width, int height) + { + // Nothing to do here for lightweights. + } + + /** + * Sets the cursor on the heavy-weight parent peer. + * Called by the MouseListener on mouse enter. + */ + public void setCursor(Cursor cursor) + { + // Nothing to do here for lightweights. + } + + public void setEnabled(boolean enabled) + { + // Nothing to do here for lightweights. + } + + public void setEventMask(long eventMask) + { + // Nothing to do here for lightweights. + } + + public void setFont(Font font) + { + // Nothing to do here for lightweights. + } + + public void setForeground(Color color) + { + // Nothing to do here for lightweights. + } + + public void setVisible(boolean visible) + { + // Nothing to do here for lightweights. + } + + public void show() + { + // Nothing to do here for lightweights. + } + + public ColorModel getColorModel() + { + // Nothing to do here for lightweights. + return null; + } + + public boolean isObscured() + { + // Nothing to do here for lightweights. + return false; + } + + public boolean canDetermineObscurity() + { + // Nothing to do here for lightweights. + return false; + } + + public void coalescePaintEvent(PaintEvent e) + { + // Nothing to do here for lightweights. + } + + public void updateCursorImmediately() + { + // Nothing to do here for lightweights. + } + + public VolatileImage createVolatileImage(int width, int height) + { + // Nothing to do here for lightweights. + return null; + } + + public boolean handlesWheelScrolling() + { + // Nothing to do here for lightweights. + return false; + } + + public void createBuffers(int x, BufferCapabilities capabilities) + throws AWTException + { + // Nothing to do here for lightweights. + } + + public Image getBackBuffer() + { + // Nothing to do here for lightweights. + return null; + } + + public void flip(BufferCapabilities.FlipContents contents) + { + // Nothing to do here for lightweights. + } + + public void destroyBuffers() + { + // Nothing to do here for lightweights. + } + + public boolean isRestackSupported() + { + // Nothing to do here for lightweights. + return false; + } + + public void cancelPendingPaint(int x, int y, int width, int height) + { + // Nothing to do here for lightweights. + } + + public void restack() + { + // Nothing to do here for lightweights. + } + + public Rectangle getBounds() + { + // Nothing to do here for lightweights. + return null; + } + + public void reparent(ContainerPeer parent) + { + // Nothing to do here for lightweights. + } + + public void setBounds(int x, int y, int z, int width, int height) + { + // Nothing to do here for lightweights. + } + + public boolean isReparentSupported() + { + // Nothing to do here for lightweights. + return true; + } + + public void layout() + { + // Nothing to do here for lightweights. + } + + public boolean requestFocus(Component lightweightChild, boolean temporary, + boolean focusedWindowChangeAllowed, + long time, sun.awt.CausedFocusEvent.Cause cause) + { + // Always grant focus request. + return true; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/GnomeDesktopPeer.java b/libjava/classpath/gnu/java/awt/peer/GnomeDesktopPeer.java new file mode 100644 index 000000000..2347371ad --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/GnomeDesktopPeer.java @@ -0,0 +1,155 @@ +/* GnomeDesktopPeer.java -- Offers a GNOME Desktop peer for DesktopPeer + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + +package gnu.java.awt.peer; + +import gnu.java.lang.CPStringBuilder; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; + +/** + * @author Mario Torre + */ +public class GnomeDesktopPeer + extends ClasspathDesktopPeer +{ + /** + * Query string to use if a GNOME desktop is detected to get the name of the + * default browser. This requires gconftool-2 (part of GNOME). + */ + private static final String BROWSER_QUERY_GNOME = + "gconftool-2 -g /desktop/gnome/url-handlers/http/command"; + + protected String getCommand(String action) + { + // check if a command already exists + String command = super.getCommand(action); + + if (command == null) + { + try + { + if (action == _BROWSE) + { + command = execQuery(BROWSER_QUERY_GNOME); + } + else if (action == _PRINT) + { + command = null; + } + else + { + command = "gnome-open"; + } + } + catch (Exception e) + { + command = null; + } + } + + return command; + } + + public void browse(URI url) throws IOException + { + checkPermissions(); + + String browser = getCommand(_BROWSE); + + if (browser == null) + throw new UnsupportedOperationException(); + + browser = browser + " " + url.toString(); + + Runtime.getRuntime().exec(browser); + } + + protected boolean supportCommand(String check) + { + if (check == _PRINT) + { + return super.supportCommand(check); + } + + return true; + } + + public void mail() throws IOException + { + checkPermissions(); + + String mail = getCommand(_MAIL); + + if (mail == null) + throw new UnsupportedOperationException(); + + Runtime.getRuntime().exec(mail + " mailto:"); + } + + protected String execQuery(String command) throws IOException + { + InputStream in = null; + CPStringBuilder output = new CPStringBuilder(); + + try + { + Process process = Runtime.getRuntime().exec(command); + + // Get the input stream and read from it + in = process.getInputStream(); + int c; + while ((c = in.read()) != - 1) + { + output.append((char) c); + } + } + finally + { + if (in != null) + in.close(); + } + + // remove %s from the string, leave only the command line + int index = output.indexOf("%s"); + output.delete(index, index + 1); + + return output.toString().trim(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/KDEDesktopPeer.java b/libjava/classpath/gnu/java/awt/peer/KDEDesktopPeer.java new file mode 100644 index 000000000..44a508435 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/KDEDesktopPeer.java @@ -0,0 +1,135 @@ +/* GnomeDesktopPeer.java -- Offers a KDE Desktop peer for DesktopPeer + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + +package gnu.java.awt.peer; + +import gnu.java.lang.CPStringBuilder; + +import java.io.IOException; +import java.io.InputStream; + +/** + * @author Mario Torre + */ +public class KDEDesktopPeer + extends ClasspathDesktopPeer +{ + /** + * Query string to use if a GNOME desktop is detected to get the name of the + * default browser. This requires gconftool-2 (part of GNOME). + */ + private static final String BROWSER_QUERY_GNOME = + "gconftool-2 -g /desktop/gnome/url-handlers/http/command"; + + protected String getCommand(String action) + { + // check if a command already exists + String command = super.getCommand(action); + + if (command == null) + { + try + { + if (action == _MAIL) + { + command = "kfmclient exec"; + } + else if (action == _PRINT) + { + command = "kprinter"; + } + else + { + command = "kfmclient openURL"; + } + } + catch (Exception e) + { + command = null; + } + } + + return command; + } + + protected boolean supportCommand(String check) + { + return true; + } + + public void mail() throws IOException + { + checkPermissions(); + + String mail = getCommand(_MAIL); + + if (mail == null) + throw new UnsupportedOperationException(); + + Runtime.getRuntime().exec(mail + " 'mailto: '"); + } + + protected String execQuery(String command) throws IOException + { + InputStream in = null; + CPStringBuilder output = new CPStringBuilder(); + + try + { + Process process = Runtime.getRuntime().exec(command); + + // Get the input stream and read from it + in = process.getInputStream(); + int c; + while ((c = in.read()) != - 1) + { + output.append((char) c); + } + } + finally + { + if (in != null) + in.close(); + } + + // remove %s from the string, leave only the command line + int index = output.indexOf("%s"); + output.delete(index, index + 1); + + return output.toString().trim(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/NativeEventLoopRunningEvent.java b/libjava/classpath/gnu/java/awt/peer/NativeEventLoopRunningEvent.java new file mode 100644 index 000000000..962ecd990 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/NativeEventLoopRunningEvent.java @@ -0,0 +1,58 @@ +/* NativeEventLoopRunningEvent.java -- communicates to EventQueue the + state of the native event loop + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer; + +import java.awt.AWTEvent; + +public class NativeEventLoopRunningEvent + extends AWTEvent +{ + private boolean running; + + public NativeEventLoopRunningEvent(Object source) + { + super(source, 2999); + running = ((Boolean) source).booleanValue(); + } + + public boolean isRunning() + { + return running; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java new file mode 100644 index 000000000..786dcf26b --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/AsyncImage.java @@ -0,0 +1,283 @@ +/* AsyncImage.java -- Loads images asynchronously + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.net.URL; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; + +/** + * Supports asynchronous loading of images. + */ +public class AsyncImage + extends Image +{ + + /** + * Returned as source as long as the image is not complete. + */ + private class NullImageSource + implements ImageProducer + { + private ArrayList consumers; + + NullImageSource() + { + consumers = new ArrayList(); + } + + public void addConsumer(ImageConsumer ic) + { + consumers.add(ic); + } + + public boolean isConsumer(ImageConsumer ic) + { + return consumers.contains(ic); + } + + public void removeConsumer(ImageConsumer ic) + { + consumers.remove(ic); + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) + { + startProduction(ic); + } + + public void startProduction(ImageConsumer ic) + { + consumers.add(ic); + for (int i = consumers.size() - 1; i >= 0; i--) + { + ImageConsumer c = (ImageConsumer) consumers.get(i); + c.setDimensions(1, 1); + ic.imageComplete(ImageConsumer.SINGLEFRAMEDONE); + } + } + + } + + /** + * Loads the image asynchronously. + */ + private class Loader + implements Runnable + { + private URL url; + Loader(URL u) + { + url = u; + } + + public void run() + { + Image image; + try + { + GtkImage gtkImage = new GtkImage(url); + image = CairoSurface.getBufferedImage(gtkImage); + } + catch (IllegalArgumentException iae) + { + image = null; + } + realImage = GtkToolkit.imageOrError(image); + synchronized (AsyncImage.this) + { + notifyObservers(ImageObserver.ALLBITS | ImageObserver.HEIGHT + | ImageObserver.WIDTH | ImageObserver.PROPERTIES); + observers = null; // Not needed anymore. + } + } + } + + /** + * The real image. This is null as long as the image is not complete. + */ + Image realImage; + + /** + * The image observers. + * + * This is package private to avoid accessor methods. + */ + HashSet observers; + + /** + * Creates a new AsyncImage that loads from the specified URL. + */ + AsyncImage(URL url) + { + observers = new HashSet(); + Loader l = new Loader(url); + Thread t = new Thread(l); + t.start(); + } + + public void flush() + { + // Nothing to do here. + } + + public Graphics getGraphics() + { + Image r = realImage; + Graphics g = null; + if (r != null) + g = r.getGraphics(); // Should we return some dummy graphics instead? + return g; + } + + public int getHeight(ImageObserver observer) + { + addObserver(observer); + int height = 0; + Image r = realImage; + if (r != null) + height = r.getHeight(observer); + return height; + } + + public Object getProperty(String name, ImageObserver observer) + { + addObserver(observer); + Image r = realImage; + Object prop = null; + if (r != null) + prop = r.getProperty(name, observer); + return prop; + } + + public ImageProducer getSource() + { + Image r = realImage; + ImageProducer source; + if (r == null) + source = new NullImageSource(); + else + source = r.getSource(); + return source; + } + + public int getWidth(ImageObserver observer) + { + addObserver(observer); + int width = 0; + Image r = realImage; + if (r != null) + width = r.getWidth(observer); + return width; + } + + void addObserver(ImageObserver obs) + { + if (obs != null) + { + synchronized (this) + { + // This field gets null when image loading is complete and we don't + // need to store any more observers. + HashSet observs = observers; + if (observs != null) + { + observs.add(obs); + } + else + { + // When the image is complete, notify the observer. Dunno if + // that's really needed, but to be sure. + obs.imageUpdate(this, ImageObserver.WIDTH + | ImageObserver.HEIGHT + |ImageObserver.ALLBITS + | ImageObserver.PROPERTIES, 0, 0, + realImage.getWidth(null), + realImage.getHeight(null)); + } + } + } + } + + static Image realImage(Image img, ImageObserver obs) + { + if (img instanceof AsyncImage) + { + ((AsyncImage) img).addObserver(obs); + Image r = ((AsyncImage) img).realImage; + if (r != null) + img = r; + } + return img; + } + + void notifyObservers(int status) + { + assert Thread.holdsLock(this); + // This field gets null when image loading is complete. + HashSet observs = observers; + if (observs != null) + { + Image r = realImage; + Iterator i = observs.iterator(); + while (i.hasNext()) + { + ImageObserver obs = (ImageObserver) i.next(); + obs.imageUpdate(this, status, 0, 0, r.getWidth(null), + r.getHeight(null)); + } + } + } + + int checkImage(ImageObserver obs) + { + addObserver(obs); + int flags = 0; + if (realImage != null) + flags = ImageObserver.ALLBITS | ImageObserver.WIDTH + | ImageObserver.HEIGHT | ImageObserver.PROPERTIES; + return flags; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java new file mode 100644 index 000000000..f9609bff6 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/BufferedImageGraphics.java @@ -0,0 +1,538 @@ +/* BufferedImageGraphics.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBufferInt; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.SinglePixelPackedSampleModel; +import java.util.WeakHashMap; + +/** + * Implementation of Graphics2D on a Cairo surface. + * + * Simutanously maintains a CairoSurface and updates the + * BufferedImage from that after each drawing operation. + */ +public class BufferedImageGraphics extends CairoGraphics2D +{ + /** + * the buffered Image. + */ + private BufferedImage image, buffer; + + /** + * Image size. + */ + private int imageWidth, imageHeight; + + /** + * The cairo surface that we actually draw on. + */ + CairoSurface surface; + + /** + * Cache BufferedImageGraphics surfaces. + */ + static WeakHashMap bufferedImages + = new WeakHashMap(); + + /** + * Its corresponding cairo_t. + */ + private long cairo_t; + + private boolean hasFastCM; + private boolean hasAlpha; + + + public BufferedImageGraphics(BufferedImage bi) + { + this.image = bi; + imageWidth = bi.getWidth(); + imageHeight = bi.getHeight(); + + if (!(image.getSampleModel() instanceof SinglePixelPackedSampleModel)) + hasFastCM = false; + else if(bi.getColorModel().equals(CairoSurface.cairoCM_opaque)) + { + hasFastCM = true; + hasAlpha = false; + } + else if(bi.getColorModel().equals(CairoSurface.cairoColorModel) + || bi.getColorModel().equals(CairoSurface.cairoCM_pre)) + { + hasFastCM = true; + hasAlpha = true; + } + else + hasFastCM = false; + + // Cache surfaces. + if( bufferedImages.get( bi ) != null ) + surface = bufferedImages.get( bi ); + else + { + surface = new CairoSurface( imageWidth, imageHeight ); + bufferedImages.put(bi, surface); + } + + cairo_t = surface.newCairoContext(); + + // Get pixels out of buffered image and set in cairo surface + Raster raster = bi.getRaster(); + int[] pixels; + + if (hasFastCM) + { + SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel)image.getSampleModel(); + int minX = image.getRaster().getSampleModelTranslateX(); + int minY = image.getRaster().getSampleModelTranslateY(); + + // Pull pixels directly out of data buffer + pixels = ((DataBufferInt)raster.getDataBuffer()).getData(); + + // Discard pixels that fall outside of the image's bounds + // (ie, this image is actually a subimage of a different image) + if (!(sm.getScanlineStride() == imageWidth && minX == 0 && minY == 0)) + { + int[] pixels2 = new int[imageWidth * imageHeight]; + int scanline = sm.getScanlineStride(); + + for (int i = 0; i < imageHeight; i++) + System.arraycopy(pixels, (i - minY) * scanline - minX, pixels2, + i * imageWidth, imageWidth); + + pixels = pixels2; + } + + // Fill the alpha channel as opaque if image does not have alpha + if( !hasAlpha ) + for(int i = 0; i < pixels.length; i++) + pixels[i] &= 0xFFFFFFFF; + } + else + { + pixels = CairoGraphics2D.findSimpleIntegerArray(image.getColorModel(), + image.getData()); + if (pixels != null) + System.arraycopy(pixels, 0, surface.getData(), + 0, pixels.length); + } + + setup( cairo_t ); + setClip(0, 0, imageWidth, imageHeight); + } + + BufferedImageGraphics(BufferedImageGraphics copyFrom) + { + image = copyFrom.image; + surface = copyFrom.surface; + cairo_t = surface.newCairoContext(); + imageWidth = copyFrom.imageWidth; + imageHeight = copyFrom.imageHeight; + + hasFastCM = copyFrom.hasFastCM; + hasAlpha = copyFrom.hasAlpha; + + copy( copyFrom, cairo_t ); + } + + /** + * Update a rectangle of the bufferedImage. This can be improved upon a lot. + */ + private void updateBufferedImage(int x, int y, int width, int height) + { + Rectangle bounds = new Rectangle(x, y, width, height); + bounds = getTransformedBounds(bounds, transform).getBounds(); + x = bounds.x; + y = bounds.y; + width = bounds.width; + height = bounds.height; + + int[] pixels = surface.getData(); + + if( x > imageWidth || y > imageHeight ) + return; + + // Deal with negative width/height. + if (height < 0) + { + y += height; + height = -height; + } + if (width < 0) + { + x += width; + width = -width; + } + + // Clip edges. + if( x < 0 ) + x = 0; + if( y < 0 ) + y = 0; + + if( x + width > imageWidth ) + width = imageWidth - x; + if( y + height > imageHeight ) + height = imageHeight - y; + + if(!hasFastCM) + { + image.setRGB(x, y, width, height, pixels, + x + y * imageWidth, imageWidth); + // The setRGB method assumes (or should assume) that pixels are NOT + // alpha-premultiplied, but Cairo stores data with premultiplication + // (thus the pixels returned in getPixels are premultiplied). + // This is ignored for consistency, however, since in + // CairoGrahpics2D.drawImage we also use non-premultiplied data + + } + else + { + int[] db = ((DataBufferInt)image.getRaster().getDataBuffer()). + getData(); + + // This should not fail, as we check the image sample model when we + // set the hasFastCM flag + SinglePixelPackedSampleModel sm = (SinglePixelPackedSampleModel)image.getSampleModel() ; + + int minX = image.getRaster().getSampleModelTranslateX(); + int minY = image.getRaster().getSampleModelTranslateY(); + + if (sm.getScanlineStride() == imageWidth && minX == 0) + { + System.arraycopy(pixels, y * imageWidth, + db, (y - minY) * imageWidth, + height * imageWidth); + } + else + { + int scanline = sm.getScanlineStride(); + for (int i = y; i < (height + y); i++) + System.arraycopy(pixels, i * imageWidth + x, db, + (i - minY) * scanline + x - minX, width); + + } + } + } + + /** + * Abstract methods. + */ + public Graphics create() + { + return new BufferedImageGraphics(this); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + return null; + } + + protected Rectangle2D getRealBounds() + { + return new Rectangle2D.Double(0.0, 0.0, imageWidth, imageHeight); + } + + public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy) + { + surface.copyAreaNative(x, y, width, height, dx, dy, surface.width); + updateBufferedImage(x + dx, y + dy, width, height); + } + + /** + * Overloaded methods that do actual drawing need to enter the gdk threads + * and also do certain things before and after. + */ + public void draw(Shape s) + { + // Find total bounds of shape + Rectangle r = findStrokedBounds(s); + if (shiftDrawCalls) + { + r.width++; + r.height++; + } + + // Do the drawing + if (comp == null || comp instanceof AlphaComposite) + { + super.draw(s); + updateBufferedImage(r.x, r.y, r.width, r.height); + } + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setStroke(this.getStroke()); + g2d.setColor(this.getColor()); + g2d.setTransform(transform); + g2d.draw(s); + + drawComposite(r.getBounds2D(), null); + } + } + + public void fill(Shape s) + { + if (comp == null || comp instanceof AlphaComposite) + { + super.fill(s); + Rectangle r = s.getBounds(); + updateBufferedImage(r.x, r.y, r.width, r.height); + } + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setColor(this.getColor()); + g2d.setTransform(transform); + g2d.fill(s); + + drawComposite(s.getBounds2D(), null); + } + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + if (comp == null || comp instanceof AlphaComposite) + { + super.drawRenderedImage(image, xform); + updateBufferedImage(0, 0, imageWidth, imageHeight); + } + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.setTransform(transform); + g2d.drawRenderedImage(image, xform); + + drawComposite(buffer.getRaster().getBounds(), null); + } + + } + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + if (comp == null || comp instanceof AlphaComposite) + { + boolean rv = super.drawImage(img, xform, bgcolor, obs); + updateBufferedImage(0, 0, imageWidth, imageHeight); + return rv; + } + else + { + // Get buffered image of source + if( !(img instanceof BufferedImage) ) + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + img = Toolkit.getDefaultToolkit().createImage(source); + } + BufferedImage bImg = (BufferedImage) img; + + // Find translated bounds + Rectangle2D bounds = new Rectangle(bImg.getMinX(), bImg.getMinY(), + bImg.getWidth(), bImg.getHeight()); + if (xform != null) + bounds = getTransformedBounds(bounds, xform); + + // Create buffer and draw image + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.drawImage(img, xform, obs); + + // Perform compositing + return drawComposite(bounds, obs); + } + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + // Find absolute bounds, in user-space, of this glyph vector + Rectangle2D bounds = gv.getLogicalBounds(); + bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(), + bounds.getWidth(), bounds.getHeight()); + + // Perform draw operation + if (comp == null || comp instanceof AlphaComposite) + { + super.drawGlyphVector(gv, x, y); + + // this returns an integer-based Rectangle (rather than a + // Rectangle2D), which takes care of any necessary rounding for us. + bounds = bounds.getBounds(); + + updateBufferedImage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), (int)bounds.getHeight()); + } + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setStroke(this.getStroke()); + g2d.setTransform(transform); + g2d.drawGlyphVector(gv, x, y); + + drawComposite(bounds, null); + } + } + + /** + * Perform composite drawing from the buffer onto the main image. + * + * The image to be composited should already be drawn into the buffer, in the + * proper place, after all necessary transforms have been applied. + * + * @param bounds The bounds to draw, in user-space. + * @param observer The image observer, if any (may be null). + * @return True on success, false on failure. + */ + private boolean drawComposite(Rectangle2D bounds, ImageObserver observer) + { + // Find bounds in device space + bounds = getTransformedBounds(bounds, transform); + + // Clip bounds by the stored clip, and by the internal buffer + Rectangle2D devClip = this.getClipInDevSpace(); + Rectangle2D.intersect(bounds, devClip, bounds); + devClip = new Rectangle(buffer.getMinX(), buffer.getMinY(), + buffer.getWidth(), buffer.getHeight()); + Rectangle2D.intersect(bounds, devClip, bounds); + + // Round bounds as needed, but be careful in our rounding + // (otherwise it may leave unpainted stripes) + double x = bounds.getX(); + double y = bounds.getY(); + double maxX = x + bounds.getWidth(); + double maxY = y + bounds.getHeight(); + x = Math.round(x); + y = Math.round(y); + bounds.setRect(x, y, Math.round(maxX - x), Math.round(maxY - y)); + + // Find subimage of internal buffer for updating + BufferedImage buffer2 = buffer; + if (!bounds.equals(buffer2.getRaster().getBounds())) + buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), + (int)bounds.getHeight()); + + // Find subimage of main image for updating + BufferedImage current = image; + current = current.getSubimage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), + (int)bounds.getHeight()); + + // Perform actual composite operation + compCtx.compose(buffer2.getRaster(), current.getRaster(), + current.getRaster()); + + // Set cairo's composite to direct SRC, since we've already done our own + // compositing + Composite oldcomp = comp; + setComposite(AlphaComposite.Src); + + // This MUST call directly into the "action" method in CairoGraphics2D, + // not one of the wrappers, to ensure that the composite isn't processed + // more than once! + boolean rv = super.drawImage(current, + AffineTransform.getTranslateInstance(bounds.getX(), + bounds.getY()), + null, null); + setComposite(oldcomp); + updateColor(); + return rv; + } + + private void createBuffer() + { + if (buffer == null) + { + buffer = new BufferedImage(image.getWidth(), image.getHeight(), + BufferedImage.TYPE_INT_ARGB); + } + else + { + Graphics2D g2d = ((Graphics2D)buffer.getGraphics()); + + g2d.setBackground(new Color(0,0,0,0)); + g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight()); + } + } + + protected ColorModel getNativeCM() + { + return image.getColorModel(); + } + + protected ColorModel getBufferCM() + { + return ColorModel.getRGBdefault(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java new file mode 100644 index 000000000..05d35c573 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoGraphics2D.java @@ -0,0 +1,2176 @@ +/* CairoGraphics2D.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import gnu.classpath.Configuration; + +import gnu.java.awt.ClasspathToolkit; + +import java.awt.AWTPermission; +import java.awt.AlphaComposite; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.CompositeContext; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Paint; +import java.awt.PaintContext; +import java.awt.Point; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.TexturePaint; +import java.awt.Toolkit; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.TextLayout; +import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.Area; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; +import java.awt.geom.NoninvertibleTransformException; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferInt; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.ImagingOpException; +import java.awt.image.MultiPixelPackedSampleModel; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.awt.image.renderable.RenderContext; +import java.awt.image.renderable.RenderableImage; +import java.text.AttributedCharacterIterator; +import java.util.HashMap; +import java.util.Map; + +/** + * This is an abstract implementation of Graphics2D on Cairo. + * + * It should be subclassed for different Cairo contexts. + * + * Note for subclassers: Apart from the constructor (see comments below), + * The following abstract methods must be implemented: + * + * Graphics create() + * GraphicsConfiguration getDeviceConfiguration() + * copyArea(int x, int y, int width, int height, int dx, int dy) + * + * Also, dispose() must be overloaded to free any native datastructures + * used by subclass and in addition call super.dispose() to free the + * native cairographics2d structure and cairo_t. + * + * @author Sven de Marothy + */ +public abstract class CairoGraphics2D extends Graphics2D +{ + static + { + if (true) // GCJ LOCAL + { + System.loadLibrary("gtkpeer"); + } + } + + /** + * Important: This is a pointer to the native cairographics2d structure + * + * DO NOT CHANGE WITHOUT CHANGING NATIVE CODE. + */ + long nativePointer; + + // Drawing state variables + /** + * The current paint + */ + Paint paint; + boolean customPaint; + + /** + * The current stroke + */ + Stroke stroke; + + /* + * Current foreground and background color. + */ + Color fg, bg; + + /** + * Current clip shape. + */ + Shape clip; + + /** + * Current transform. + */ + AffineTransform transform; + + /** + * Current font. + */ + Font font; + + /** + * The current compositing context, if any. + */ + Composite comp; + CompositeContext compCtx; + + /** + * Rendering hint map. + */ + private RenderingHints hints; + + /** + * Status of the anti-alias flag in cairo. + */ + private boolean antialias = false; + private boolean ignoreAA = false; + + /** + * Some operations (drawing rather than filling) require that their + * coords be shifted to land on 0.5-pixel boundaries, in order to land on + * "middle of pixel" coordinates and light up complete pixels. + */ + protected boolean shiftDrawCalls = false; + + /** + * Keep track if the first clip to be set, which is restored on setClip(null); + */ + private boolean firstClip = true; + private Shape originalClip; + + /** + * Stroke used for 3DRects + */ + private static BasicStroke draw3DRectStroke = new BasicStroke(); + + static ColorModel rgb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF); + static ColorModel argb32 = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, + 0xFF000000); + + /** + * Native constants for interpolation methods. + * Note, this corresponds to an enum in native/jni/gtk-peer/cairographics2d.h + */ + public static final int INTERPOLATION_NEAREST = 0, + INTERPOLATION_BILINEAR = 1, + INTERPOLATION_BICUBIC = 5, + ALPHA_INTERPOLATION_SPEED = 2, + ALPHA_INTERPOLATION_QUALITY = 3, + ALPHA_INTERPOLATION_DEFAULT = 4; + // TODO: Does ALPHA_INTERPOLATION really correspond to CAIRO_FILTER_FAST/BEST/GOOD? + + /** + * Constructor does nothing. + */ + public CairoGraphics2D() + { + } + + /** + * Sets up the default values and allocates the native cairographics2d structure + * @param cairo_t_pointer a native pointer to a cairo_t of the context. + */ + public void setup(long cairo_t_pointer) + { + nativePointer = init(cairo_t_pointer); + setRenderingHints(new RenderingHints(getDefaultHints())); + setFont(new Font("SansSerif", Font.PLAIN, 12)); + setColor(Color.black); + setBackground(Color.white); + setPaint(Color.black); + setStroke(new BasicStroke()); + setTransform(new AffineTransform()); + cairoSetAntialias(nativePointer, antialias); + } + + /** + * Same as above, but copies the state of another CairoGraphics2D. + */ + public void copy(CairoGraphics2D g, long cairo_t_pointer) + { + nativePointer = init(cairo_t_pointer); + paint = g.paint; + stroke = g.stroke; + setRenderingHints(g.hints); + + Color foreground; + + if (g.fg.getAlpha() != -1) + foreground = new Color(g.fg.getRed(), g.fg.getGreen(), g.fg.getBlue(), + g.fg.getAlpha()); + else + foreground = new Color(g.fg.getRGB()); + + if (g.bg != null) + { + if (g.bg.getAlpha() != -1) + bg = new Color(g.bg.getRed(), g.bg.getGreen(), g.bg.getBlue(), + g.bg.getAlpha()); + else + bg = new Color(g.bg.getRGB()); + } + + firstClip = g.firstClip; + originalClip = g.originalClip; + clip = g.getClip(); + + if (g.transform == null) + transform = null; + else + transform = new AffineTransform(g.transform); + + setFont(g.font); + setColor(foreground); + setBackground(bg); + setPaint(paint); + setStroke(stroke); + setTransformImpl(transform); + setClip(clip); + setComposite(comp); + + antialias = !g.antialias; + setAntialias(g.antialias); + } + + /** + * Generic destructor - call the native dispose() method. + */ + public void finalize() + { + dispose(); + } + + /** + * Disposes the native cairographics2d structure, including the + * cairo_t and any gradient stuff, if allocated. + * Subclasses should of course overload and call this if + * they have additional native structures. + */ + public void dispose() + { + disposeNative(nativePointer); + nativePointer = 0; + if (compCtx != null) + compCtx.dispose(); + } + + /** + * Allocate the cairographics2d structure and set the cairo_t pointer in it. + * @param pointer - a cairo_t pointer, casted to a long. + */ + protected native long init(long pointer); + + /** + * These are declared abstract as there may be context-specific issues. + */ + public abstract Graphics create(); + + public abstract GraphicsConfiguration getDeviceConfiguration(); + + protected abstract void copyAreaImpl(int x, int y, int width, int height, + int dx, int dy); + + + /** + * Find the bounds of this graphics context, in device space. + * + * @return the bounds in device-space + */ + protected abstract Rectangle2D getRealBounds(); + + ////// Native Methods //////////////////////////////////////////////////// + + /** + * Dispose of allocate native resouces. + */ + public native void disposeNative(long pointer); + + /** + * Draw pixels as an RGBA int matrix + * @param w - width + * @param h - height + * @param stride - stride of the array width + * @param i2u - affine transform array + */ + protected native void drawPixels(long pointer, int[] pixels, int w, int h, + int stride, double[] i2u, double alpha, + int interpolation); + + protected native void setGradient(long pointer, double x1, double y1, + double x2, double y2, + int r1, int g1, int b1, int a1, int r2, + int g2, int b2, int a2, boolean cyclic); + + protected native void setPaintPixels(long pointer, int[] pixels, int w, + int h, int stride, boolean repeat, + int x, int y); + + /** + * Set the current transform matrix + */ + protected native void cairoSetMatrix(long pointer, double[] m); + + /** + * Scaling method + */ + protected native void cairoScale(long pointer, double x, double y); + + /** + * Set the compositing operator + */ + protected native void cairoSetOperator(long pointer, int cairoOperator); + + /** + * Sets the current color in RGBA as a 0.0-1.0 double + */ + protected native void cairoSetRGBAColor(long pointer, double red, double green, + double blue, double alpha); + + /** + * Sets the current winding rule in Cairo + */ + protected native void cairoSetFillRule(long pointer, int cairoFillRule); + + /** + * Set the line style, cap, join and miter limit. + * Cap and join parameters are in the BasicStroke enumerations. + */ + protected native void cairoSetLine(long pointer, double width, int cap, + int join, double miterLimit); + + /** + * Set the dash style + */ + protected native void cairoSetDash(long pointer, double[] dashes, int ndash, + double offset); + + /* + * Draws a Glyph Vector + */ + protected native void cairoDrawGlyphVector(long pointer, GdkFontPeer font, + float x, float y, int n, + int[] codes, float[] positions, long[] fontset); + + /** + * Set the font in cairo. + */ + protected native void cairoSetFont(long pointer, GdkFontPeer font); + + /** + * Appends a rectangle to the current path + */ + protected native void cairoRectangle(long pointer, double x, double y, + double width, double height); + + /** + * Appends an arc to the current path + */ + protected native void cairoArc(long pointer, double x, double y, + double radius, double angle1, double angle2); + + /** + * Save / restore a cairo path + */ + protected native void cairoSave(long pointer); + protected native void cairoRestore(long pointer); + + /** + * New current path + */ + protected native void cairoNewPath(long pointer); + + /** + * Close current path + */ + protected native void cairoClosePath(long pointer); + + /** moveTo */ + protected native void cairoMoveTo(long pointer, double x, double y); + + /** lineTo */ + protected native void cairoLineTo(long pointer, double x, double y); + + /** Cubic curve-to */ + protected native void cairoCurveTo(long pointer, double x1, double y1, + double x2, double y2, + double x3, double y3); + + /** + * Stroke current path + */ + protected native void cairoStroke(long pointer); + + /** + * Fill current path + */ + protected native void cairoFill(long pointer, double alpha); + + /** + * Clip current path + */ + protected native void cairoClip(long pointer); + + /** + * Clear clip + */ + protected native void cairoResetClip(long pointer); + + /** + * Set antialias. + */ + protected native void cairoSetAntialias(long pointer, boolean aa); + + + ///////////////////////// TRANSFORMS /////////////////////////////////// + /** + * Set the current transform + */ + public void setTransform(AffineTransform tx) + { + // Transform clip into target space using the old transform. + updateClip(transform); + + // Update the native transform. + setTransformImpl(tx); + + // Transform the clip back into user space using the inverse new transform. + try + { + updateClip(transform.createInverse()); + } + catch (NoninvertibleTransformException ex) + { + // TODO: How can we deal properly with this? + ex.printStackTrace(); + } + + if (clip != null) + setClip(clip); + } + + private void setTransformImpl(AffineTransform tx) + { + transform = tx; + if (transform != null) + { + double[] m = new double[6]; + transform.getMatrix(m); + cairoSetMatrix(nativePointer, m); + } + } + + public void transform(AffineTransform tx) + { + if (transform == null) + transform = new AffineTransform(tx); + else + transform.concatenate(tx); + + if (clip != null) + { + try + { + AffineTransform clipTransform = tx.createInverse(); + updateClip(clipTransform); + } + catch (NoninvertibleTransformException ex) + { + // TODO: How can we deal properly with this? + ex.printStackTrace(); + } + } + + setTransformImpl(transform); + } + + public void rotate(double theta) + { + transform(AffineTransform.getRotateInstance(theta)); + } + + public void rotate(double theta, double x, double y) + { + transform(AffineTransform.getRotateInstance(theta, x, y)); + } + + public void scale(double sx, double sy) + { + transform(AffineTransform.getScaleInstance(sx, sy)); + } + + /** + * Translate the system of the co-ordinates. As translation is a frequent + * operation, it is done in an optimised way, unlike scaling and rotating. + */ + public void translate(double tx, double ty) + { + if (transform != null) + transform.translate(tx, ty); + else + transform = AffineTransform.getTranslateInstance(tx, ty); + + if (clip != null) + { + // FIXME: this should actuall try to transform the shape + // rather than degrade to bounds. + if (clip instanceof Rectangle2D) + { + Rectangle2D r = (Rectangle2D) clip; + r.setRect(r.getX() - tx, r.getY() - ty, r.getWidth(), + r.getHeight()); + } + else + { + AffineTransform clipTransform = + AffineTransform.getTranslateInstance(-tx, -ty); + updateClip(clipTransform); + } + } + + setTransformImpl(transform); + } + + public void translate(int x, int y) + { + translate((double) x, (double) y); + } + + public void shear(double shearX, double shearY) + { + transform(AffineTransform.getShearInstance(shearX, shearY)); + } + + ///////////////////////// DRAWING STATE /////////////////////////////////// + + public void clip(Shape s) + { + // Do not touch clip when s == null. + if (s == null) + { + // The spec says this should clear the clip. The reference + // implementation throws a NullPointerException instead. I think, + // in this case we should conform to the specs, as it shouldn't + // affect compatibility. + setClip(null); + return; + } + + // If the current clip is still null, initialize it. + if (clip == null) + { + clip = getRealBounds(); + } + + // This is so common, let's optimize this. + if (clip instanceof Rectangle2D && s instanceof Rectangle2D) + { + Rectangle2D clipRect = (Rectangle2D) clip; + Rectangle2D r = (Rectangle2D) s; + Rectangle2D.intersect(clipRect, r, clipRect); + setClip(clipRect); + } + else + { + Area current; + if (clip instanceof Area) + current = (Area) clip; + else + current = new Area(clip); + + Area intersect; + if (s instanceof Area) + intersect = (Area) s; + else + intersect = new Area(s); + + current.intersect(intersect); + clip = current; + // Call setClip so that the native side gets notified. + setClip(clip); + } + } + + public Paint getPaint() + { + return paint; + } + + public AffineTransform getTransform() + { + return (AffineTransform) transform.clone(); + } + + public void setPaint(Paint p) + { + if (p == null) + return; + + paint = p; + if (paint instanceof Color) + { + setColor((Color) paint); + customPaint = false; + } + + else if (paint instanceof TexturePaint) + { + TexturePaint tp = (TexturePaint) paint; + BufferedImage img = tp.getImage(); + + // map the image to the anchor rectangle + int width = (int) tp.getAnchorRect().getWidth(); + int height = (int) tp.getAnchorRect().getHeight(); + + double scaleX = width / (double) img.getWidth(); + double scaleY = height / (double) img.getHeight(); + + AffineTransform at = new AffineTransform(scaleX, 0, 0, scaleY, 0, 0); + AffineTransformOp op = new AffineTransformOp(at, getRenderingHints()); + BufferedImage texture = op.filter(img, null); + int[] pixels = texture.getRGB(0, 0, width, height, null, 0, width); + setPaintPixels(nativePointer, pixels, width, height, width, true, 0, 0); + customPaint = false; + } + + else if (paint instanceof GradientPaint) + { + GradientPaint gp = (GradientPaint) paint; + Point2D p1 = gp.getPoint1(); + Point2D p2 = gp.getPoint2(); + Color c1 = gp.getColor1(); + Color c2 = gp.getColor2(); + setGradient(nativePointer, p1.getX(), p1.getY(), p2.getX(), p2.getY(), + c1.getRed(), c1.getGreen(), c1.getBlue(), c1.getAlpha(), + c2.getRed(), c2.getGreen(), c2.getBlue(), c2.getAlpha(), + gp.isCyclic()); + customPaint = false; + } + else + { + customPaint = true; + } + } + + /** + * Sets a custom paint + * + * @param bounds the bounding box, in user space + */ + protected void setCustomPaint(Rectangle bounds) + { + if (paint instanceof Color || paint instanceof TexturePaint + || paint instanceof GradientPaint) + return; + + int userX = bounds.x; + int userY = bounds.y; + int userWidth = bounds.width; + int userHeight = bounds.height; + + // Find bounds in device space + Rectangle2D bounds2D = getTransformedBounds(bounds, transform); + int deviceX = (int)bounds2D.getX(); + int deviceY = (int)bounds2D.getY(); + int deviceWidth = (int)Math.ceil(bounds2D.getWidth()); + int deviceHeight = (int)Math.ceil(bounds2D.getHeight()); + + // Get raster of the paint background + PaintContext pc = paint.createContext(CairoSurface.cairoColorModel, + new Rectangle(deviceX, deviceY, + deviceWidth, + deviceHeight), + bounds, + transform, hints); + + Raster raster = pc.getRaster(deviceX, deviceY, deviceWidth, + deviceHeight); + + // Clear the transform matrix in Cairo, since the raster returned by the + // PaintContext is already in device-space + AffineTransform oldTx = new AffineTransform(transform); + setTransformImpl(new AffineTransform()); + + // Set pixels in cairo, aligning the top-left of the background image + // to the top-left corner in device space + if (pc.getColorModel().equals(CairoSurface.cairoColorModel) + && raster.getSampleModel().getTransferType() == DataBuffer.TYPE_INT) + { + // Use a fast copy if the paint context can uses a Cairo-compatible + // color model + setPaintPixels(nativePointer, + (int[])raster.getDataElements(0, 0, deviceWidth, + deviceHeight, null), + deviceWidth, deviceHeight, deviceWidth, false, + deviceX, deviceY); + } + + else if (pc.getColorModel().equals(CairoSurface.cairoCM_opaque) + && raster.getSampleModel().getTransferType() == DataBuffer.TYPE_INT) + { + // We can also optimize if the context uses a similar color model + // but without an alpha channel; we just add the alpha + int[] pixels = (int[])raster.getDataElements(0, 0, deviceWidth, + deviceHeight, null); + + for (int i = 0; i < pixels.length; i++) + pixels[i] = 0xff000000 | (pixels[i] & 0x00ffffff); + + setPaintPixels(nativePointer, pixels, deviceWidth, deviceHeight, + deviceWidth, false, deviceX, deviceY); + } + + else + { + // Fall back on wrapping the raster in a BufferedImage, and + // use BufferedImage.getRGB() to do color-model conversion + WritableRaster wr = Raster.createWritableRaster(raster.getSampleModel(), + new Point(raster.getMinX(), + raster.getMinY())); + wr.setRect(raster); + + BufferedImage img2 = new BufferedImage(pc.getColorModel(), wr, + pc.getColorModel().isAlphaPremultiplied(), + null); + + setPaintPixels(nativePointer, + img2.getRGB(0, 0, deviceWidth, deviceHeight, null, 0, + deviceWidth), + deviceWidth, deviceHeight, deviceWidth, false, + deviceX, deviceY); + } + + // Restore transform + setTransformImpl(oldTx); + } + + public Stroke getStroke() + { + return stroke; + } + + public void setStroke(Stroke st) + { + stroke = st; + if (stroke instanceof BasicStroke) + { + BasicStroke bs = (BasicStroke) stroke; + cairoSetLine(nativePointer, bs.getLineWidth(), bs.getEndCap(), + bs.getLineJoin(), bs.getMiterLimit()); + + float[] dashes = bs.getDashArray(); + if (dashes != null) + { + double[] double_dashes = new double[dashes.length]; + for (int i = 0; i < dashes.length; i++) + double_dashes[i] = dashes[i]; + + cairoSetDash(nativePointer, double_dashes, double_dashes.length, + (double) bs.getDashPhase()); + } + else + cairoSetDash(nativePointer, new double[0], 0, 0.0); + } + } + + /** + * Utility method to find the bounds of a shape, including the stroke width. + * + * @param s the shape + * @return the bounds of the shape, including stroke width + */ + protected Rectangle findStrokedBounds(Shape s) + { + Rectangle r = s.getBounds(); + + if (stroke instanceof BasicStroke) + { + int strokeWidth = (int)Math.ceil(((BasicStroke)stroke).getLineWidth()); + r.x -= strokeWidth / 2; + r.y -= strokeWidth / 2; + r.height += strokeWidth; + r.width += strokeWidth; + } + else + { + Shape s2 = stroke.createStrokedShape(s); + r = s2.getBounds(); + } + + return r; + } + + public void setPaintMode() + { + setComposite(AlphaComposite.SrcOver); + } + + public void setXORMode(Color c) + { + // FIXME: implement + } + + public void setColor(Color c) + { + if (c == null) + c = Color.BLACK; + + fg = c; + paint = c; + updateColor(); + } + + /** + * Set the current fg value as the cairo color. + */ + void updateColor() + { + if (fg == null) + fg = Color.BLACK; + + cairoSetRGBAColor(nativePointer, fg.getRed() / 255.0, + fg.getGreen() / 255.0,fg.getBlue() / 255.0, + fg.getAlpha() / 255.0); + } + + public Color getColor() + { + return fg; + } + + public void clipRect(int x, int y, int width, int height) + { + if (clip == null) + setClip(new Rectangle(x, y, width, height)); + else if (clip instanceof Rectangle) + { + computeIntersection(x, y, width, height, (Rectangle) clip); + setClip(clip); + } + else + clip(new Rectangle(x, y, width, height)); + } + + public Shape getClip() + { + if (clip == null) + return null; + else if (clip instanceof Rectangle2D) + return clip.getBounds2D(); //getClipInDevSpace(); + else + { + GeneralPath p = new GeneralPath(); + PathIterator pi = clip.getPathIterator(null); + p.append(pi, false); + return p; + } + } + + public Rectangle getClipBounds() + { + if (clip == null) + return null; + else + return clip.getBounds(); + } + + protected Rectangle2D getClipInDevSpace() + { + Rectangle2D uclip = clip.getBounds2D(); + if (transform == null) + return uclip; + else + return getTransformedBounds(clip.getBounds2D(), transform); + } + + public void setClip(int x, int y, int width, int height) + { + if( width < 0 || height < 0 ) + return; + + setClip(new Rectangle2D.Double(x, y, width, height)); + } + + public void setClip(Shape s) + { + // The first time the clip is set, save it as the original clip + // to reset to on s == null. We can rely on this being non-null + // because the constructor in subclasses is expected to set the + // initial clip properly. + if( firstClip ) + { + originalClip = s; + firstClip = false; + } + + clip = s; + cairoResetClip(nativePointer); + + if (clip != null) + { + cairoNewPath(nativePointer); + if (clip instanceof Rectangle2D) + { + Rectangle2D r = (Rectangle2D) clip; + cairoRectangle(nativePointer, r.getX(), r.getY(), r.getWidth(), + r.getHeight()); + } + else + walkPath(clip.getPathIterator(null), false); + + cairoClip(nativePointer); + } + } + + public void setBackground(Color c) + { + if (c == null) + c = Color.WHITE; + bg = c; + } + + public Color getBackground() + { + return bg; + } + + /** + * Return the current composite. + */ + public Composite getComposite() + { + if (comp == null) + return AlphaComposite.SrcOver; + else + return comp; + } + + /** + * Sets the current composite context. + */ + public void setComposite(Composite comp) + { + if (this.comp == comp) + return; + + this.comp = comp; + if (compCtx != null) + compCtx.dispose(); + compCtx = null; + + if (comp instanceof AlphaComposite) + { + AlphaComposite a = (AlphaComposite) comp; + cairoSetOperator(nativePointer, a.getRule()); + } + + else + { + cairoSetOperator(nativePointer, AlphaComposite.SRC_OVER); + + if (comp != null) + { + // FIXME: this check is only required "if this Graphics2D + // context is drawing to a Component on the display screen". + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new AWTPermission("readDisplayPixels")); + + compCtx = comp.createContext(getBufferCM(), getNativeCM(), hints); + } + } + } + + /** + * Returns the Colour Model describing the native, raw image data for this + * specific peer. + * + * @return ColorModel the ColorModel of native data in this peer + */ + protected abstract ColorModel getNativeCM(); + + /** + * Returns the Color Model describing the buffer that this peer uses + * for custom composites. + * + * @return ColorModel the ColorModel of the composite buffer in this peer. + */ + protected ColorModel getBufferCM() + { + // This may be overridden by some subclasses + return getNativeCM(); + } + + ///////////////////////// DRAWING PRIMITIVES /////////////////////////////////// + + public void draw(Shape s) + { + if ((stroke != null && ! (stroke instanceof BasicStroke)) + || (comp instanceof AlphaComposite && ((AlphaComposite) comp).getAlpha() != 1.0)) + { + // Cairo doesn't support stroking with alpha, so we create the stroked + // shape and fill with alpha instead + fill(stroke.createStrokedShape(s)); + return; + } + + if (customPaint) + { + Rectangle r = findStrokedBounds(s); + setCustomPaint(r); + } + + setAntialias(!hints.get(RenderingHints.KEY_ANTIALIASING) + .equals(RenderingHints.VALUE_ANTIALIAS_OFF)); + createPath(s, true); + cairoStroke(nativePointer); + } + + public void fill(Shape s) + { + createPath(s, false); + + if (customPaint) + setCustomPaint(s.getBounds()); + + setAntialias(!hints.get(RenderingHints.KEY_ANTIALIASING) + .equals(RenderingHints.VALUE_ANTIALIAS_OFF)); + double alpha = 1.0; + if (comp instanceof AlphaComposite) + alpha = ((AlphaComposite) comp).getAlpha(); + cairoFill(nativePointer, alpha); + } + + private void createPath(Shape s, boolean isDraw) + { + cairoNewPath(nativePointer); + + // Optimize rectangles, since there is a direct Cairo function + if (s instanceof Rectangle2D) + { + Rectangle2D r = (Rectangle2D) s; + + // Pixels need to be shifted in draw operations to ensure that they + // light up entire pixels, but we also need to make sure the rectangle + // does not get distorted by this shifting operation + double x = shiftX(r.getX(),shiftDrawCalls && isDraw); + double y = shiftY(r.getY(), shiftDrawCalls && isDraw); + double w = Math.round(r.getWidth()); + double h = Math.round(r.getHeight()); + cairoRectangle(nativePointer, x, y, w, h); + } + + // Lines are easy too + else if (s instanceof Line2D) + { + Line2D l = (Line2D) s; + cairoMoveTo(nativePointer, shiftX(l.getX1(), shiftDrawCalls && isDraw), + shiftY(l.getY1(), shiftDrawCalls && isDraw)); + cairoLineTo(nativePointer, shiftX(l.getX2(), shiftDrawCalls && isDraw), + shiftY(l.getY2(), shiftDrawCalls && isDraw)); + } + + // We can optimize ellipses too; however we don't bother optimizing arcs: + // the iterator is fast enough (an ellipse requires 5 steps using the + // iterator, while most arcs are only 2-3) + else if (s instanceof Ellipse2D) + { + Ellipse2D e = (Ellipse2D) s; + + double radius = Math.min(e.getHeight(), e.getWidth()) / 2; + + // Cairo only draws circular shapes, but we can use a stretch to make + // them into ellipses + double xscale = 1, yscale = 1; + if (e.getHeight() != e.getWidth()) + { + cairoSave(nativePointer); + + if (e.getHeight() < e.getWidth()) + xscale = e.getWidth() / (radius * 2); + else + yscale = e.getHeight() / (radius * 2); + + if (xscale != 1 || yscale != 1) + cairoScale(nativePointer, xscale, yscale); + } + + cairoArc(nativePointer, + shiftX(e.getCenterX() / xscale, shiftDrawCalls && isDraw), + shiftY(e.getCenterY() / yscale, shiftDrawCalls && isDraw), + radius, 0, Math.PI * 2); + + if (xscale != 1 || yscale != 1) + cairoRestore(nativePointer); + } + + // All other shapes are broken down and drawn in steps using the + // PathIterator + else + walkPath(s.getPathIterator(null), shiftDrawCalls && isDraw); + } + + /** + * Note that the rest of the drawing methods go via fill() or draw() for the drawing, + * although subclasses may with to overload these methods where context-specific + * optimizations are possible (e.g. bitmaps and fillRect(int, int, int, int) + */ + + public void clearRect(int x, int y, int width, int height) + { + if (bg != null) + cairoSetRGBAColor(nativePointer, bg.getRed() / 255.0, + bg.getGreen() / 255.0, bg.getBlue() / 255.0, + bg.getAlpha() / 255.0); + + Composite oldcomp = comp; + setComposite(AlphaComposite.Src); + fillRect(x, y, width, height); + + setComposite(oldcomp); + updateColor(); + } + + public void draw3DRect(int x, int y, int width, int height, boolean raised) + { + Stroke tmp = stroke; + setStroke(draw3DRectStroke); + super.draw3DRect(x, y, width, height, raised); + setStroke(tmp); + } + + public void drawArc(int x, int y, int width, int height, int startAngle, + int arcAngle) + { + draw(new Arc2D.Double((double) x, (double) y, (double) width, + (double) height, (double) startAngle, + (double) arcAngle, Arc2D.OPEN)); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + // The coordinates being pairwise identical means one wants + // to draw a single pixel. This is emulated by drawing + // a one pixel sized rectangle. + if (x1 == x2 && y1 == y2) + fill(new Rectangle(x1, y1, 1, 1)); + else + draw(new Line2D.Double(x1, y1, x2, y2)); + } + + public void drawRect(int x, int y, int width, int height) + { + draw(new Rectangle(x, y, width, height)); + } + + public void fillArc(int x, int y, int width, int height, int startAngle, + int arcAngle) + { + fill(new Arc2D.Double((double) x, (double) y, (double) width, + (double) height, (double) startAngle, + (double) arcAngle, Arc2D.PIE)); + } + + public void fillRect(int x, int y, int width, int height) + { + fill (new Rectangle(x, y, width, height)); + } + + public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + fill(new Polygon(xPoints, yPoints, nPoints)); + } + + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + draw(new Polygon(xPoints, yPoints, nPoints)); + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) + { + for (int i = 1; i < nPoints; i++) + draw(new Line2D.Double(xPoints[i - 1], yPoints[i - 1], + xPoints[i], yPoints[i])); + } + + public void drawOval(int x, int y, int width, int height) + { + drawArc(x, y, width, height, 0, 360); + } + + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) + { + draw(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight)); + } + + public void fillOval(int x, int y, int width, int height) + { + fillArc(x, y, width, height, 0, 360); + } + + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) + { + fill(new RoundRectangle2D.Double(x, y, width, height, arcWidth, arcHeight)); + } + + /** + * CopyArea - performs clipping to the native surface as a convenience + * (requires getRealBounds). Then calls copyAreaImpl. + */ + public void copyArea(int ox, int oy, int owidth, int oheight, + int odx, int ody) + { + // FIXME: does this handle a rotation transform properly? + // (the width/height might not be correct) + Point2D pos = transform.transform(new Point2D.Double(ox, oy), + (Point2D) null); + Point2D dim = transform.transform(new Point2D.Double(ox + owidth, + oy + oheight), + (Point2D) null); + Point2D p2 = transform.transform(new Point2D.Double(ox + odx, oy + ody), + (Point2D) null); + int x = (int)pos.getX(); + int y = (int)pos.getY(); + int width = (int)(dim.getX() - pos.getX()); + int height = (int)(dim.getY() - pos.getY()); + int dx = (int)(p2.getX() - pos.getX()); + int dy = (int)(p2.getY() - pos.getY()); + + Rectangle2D r = getRealBounds(); + + if( width <= 0 || height <= 0 ) + return; + // Return if outside the surface + if( x + dx > r.getWidth() || y + dy > r.getHeight() ) + return; + + if( x + dx + width < r.getX() || y + dy + height < r.getY() ) + return; + + // Clip edges if necessary + if( x + dx < r.getX() ) // left + { + width = x + dx + width; + x = (int)r.getX() - dx; + } + + if( y + dy < r.getY() ) // top + { + height = y + dy + height; + y = (int)r.getY() - dy; + } + + if( x + dx + width >= r.getWidth() ) // right + width = (int)r.getWidth() - dx - x; + + if( y + dy + height >= r.getHeight() ) // bottom + height = (int)r.getHeight() - dy - y; + + copyAreaImpl(x, y, width, height, dx, dy); + } + + ///////////////////////// RENDERING HINTS /////////////////////////////////// + + public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) + { + hints.put(hintKey, hintValue); + + shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE) + || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT); + } + + public Object getRenderingHint(RenderingHints.Key hintKey) + { + return hints.get(hintKey); + } + + public void setRenderingHints(Map hints) + { + this.hints = new RenderingHints(getDefaultHints()); + this.hints.putAll(hints); + + shiftDrawCalls = hints.containsValue(RenderingHints.VALUE_STROKE_NORMALIZE) + || hints.containsValue(RenderingHints.VALUE_STROKE_DEFAULT); + + if (compCtx != null) + { + compCtx.dispose(); + compCtx = comp.createContext(getNativeCM(), getNativeCM(), this.hints); + } + } + + public void addRenderingHints(Map hints) + { + this.hints.putAll(hints); + } + + public RenderingHints getRenderingHints() + { + return hints; + } + + private int getInterpolation() + { + if (this.hints.containsValue(RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR)) + return INTERPOLATION_NEAREST; + + else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BILINEAR)) + return INTERPOLATION_BILINEAR; + + else if (hints.containsValue(RenderingHints.VALUE_INTERPOLATION_BICUBIC)) + return INTERPOLATION_BICUBIC; + + else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_SPEED)) + return ALPHA_INTERPOLATION_SPEED; + + else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY)) + return ALPHA_INTERPOLATION_QUALITY; + + else if (hints.containsValue(RenderingHints.VALUE_ALPHA_INTERPOLATION_DEFAULT)) + return ALPHA_INTERPOLATION_DEFAULT; + + // Do bilinear interpolation as default + return INTERPOLATION_BILINEAR; + } + + /** + * Set antialias if needed. If the ignoreAA flag is set, this method will + * return without doing anything. + * + * @param needAA RenderingHints.VALUE_ANTIALIAS_ON or RenderingHints.VALUE_ANTIALIAS_OFF + */ + private void setAntialias(boolean needAA) + { + if (ignoreAA) + return; + + if (needAA != antialias) + { + antialias = !antialias; + cairoSetAntialias(nativePointer, antialias); + } + } + + ///////////////////////// IMAGE. METHODS /////////////////////////////////// + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + if (img == null) + return false; + + if (xform == null) + xform = new AffineTransform(); + + // In this case, xform is an AffineTransform that transforms bounding + // box of the specified image from image space to user space. However + // when we pass this transform to cairo, cairo will use this transform + // to map "user coordinates" to "pixel" coordinates, which is the + // other way around. Therefore to get the "user -> pixel" transform + // that cairo wants from "image -> user" transform that we currently + // have, we will need to invert the transformation matrix. + AffineTransform invertedXform; + + try + { + invertedXform = xform.createInverse(); + } + catch (NoninvertibleTransformException e) + { + throw new ImagingOpException("Unable to invert transform " + + xform.toString()); + } + + // Unrecognized image - convert to a BufferedImage + // Note - this can get us in trouble when the gdk lock is re-acquired. + // for example by VolatileImage. See ComponentGraphics for how we work + // around this. + img = AsyncImage.realImage(img, obs); + if( !(img instanceof BufferedImage) ) + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + img = Toolkit.getDefaultToolkit().createImage(source); + } + + BufferedImage b = (BufferedImage) img; + Raster raster; + double[] i2u = new double[6]; + int width = b.getWidth(); + int height = b.getHeight(); + + // If this BufferedImage has a BufferedImageGraphics object, + // use the cached CairoSurface that BIG is drawing onto + + if( BufferedImageGraphics.bufferedImages.get( b ) != null ) + raster = BufferedImageGraphics.bufferedImages.get( b ); + else + raster = b.getRaster(); + + invertedXform.getMatrix(i2u); + + double alpha = 1.0; + if (comp instanceof AlphaComposite) + alpha = ((AlphaComposite) comp).getAlpha(); + + if(raster instanceof CairoSurface + && ((CairoSurface)raster).sharedBuffer == true) + { + drawCairoSurface((CairoSurface)raster, xform, alpha, getInterpolation()); + updateColor(); + return true; + } + + if( bgcolor != null ) + { + Color oldColor = bg; + setBackground(bgcolor); + + Rectangle2D bounds = new Rectangle2D.Double(0, 0, width, height); + bounds = getTransformedBounds(bounds, xform); + + clearRect((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), (int)bounds.getHeight()); + + setBackground(oldColor); + } + + int[] pixels = b.getRGB(0, 0, width, height, null, 0, width); + // FIXME: The above method returns data in the standard ARGB colorspace, + // meaning data should NOT be alpha pre-multiplied; however Cairo expects + // data to be premultiplied. + + cairoSave(nativePointer); + Rectangle2D bounds = new Rectangle2D.Double(0, 0, width, height); + bounds = getTransformedBounds(bounds, xform); + cairoRectangle(nativePointer, bounds.getX(), bounds.getY(), + bounds.getWidth(), bounds.getHeight()); + cairoClip(nativePointer); + + drawPixels(nativePointer, pixels, width, height, width, i2u, alpha, + getInterpolation()); + + cairoRestore(nativePointer); + + // Cairo seems to lose the current color which must be restored. + updateColor(); + return true; + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + drawRaster(image.getColorModel(), image.getData(), xform, null); + } + + public void drawRenderableImage(RenderableImage image, AffineTransform xform) + { + drawRenderedImage(image.createRendering(new RenderContext(xform)), xform); + } + + public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) + { + return drawImage(img, xform, null, obs); + } + + public void drawImage(BufferedImage image, BufferedImageOp op, int x, int y) + { + Image filtered = image; + if (op != null) + filtered = op.filter(image, null); + drawImage(filtered, new AffineTransform(1f, 0f, 0f, 1f, x, y), null, null); + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + return drawImage(img, new AffineTransform(1f, 0f, 0f, 1f, x, y), null, + observer); + } + + public boolean drawImage(Image img, int x, int y, Color bgcolor, + ImageObserver observer) + { + return drawImage(img, x, y, img.getWidth(observer), + img.getHeight(observer), bgcolor, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + double scaleX = width / (double) img.getWidth(observer); + double scaleY = height / (double) img.getHeight(observer); + if( scaleX == 0 || scaleY == 0 ) + return true; + + return drawImage(img, new AffineTransform(scaleX, 0f, 0f, scaleY, x, y), + bgcolor, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) + { + return drawImage(img, x, y, width, height, null, observer); + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, Color bgcolor, + ImageObserver observer) + { + if (img == null) + return false; + + int sourceWidth = sx2 - sx1; + int sourceHeight = sy2 - sy1; + + int destWidth = dx2 - dx1; + int destHeight = dy2 - dy1; + + if(destWidth == 0 || destHeight == 0 || sourceWidth == 0 || + sourceHeight == 0) + return true; + + double scaleX = destWidth / (double) sourceWidth; + double scaleY = destHeight / (double) sourceHeight; + + // FIXME: Avoid using an AT if possible here - it's at least twice as slow. + + Shape oldClip = getClip(); + int cx, cy, cw, ch; + if( dx1 < dx2 ) + { cx = dx1; cw = dx2 - dx1; } + else + { cx = dx2; cw = dx1 - dx2; } + if( dy1 < dy2 ) + { cy = dy1; ch = dy2 - dy1; } + else + { cy = dy2; ch = dy1 - dy2; } + + clipRect( cx, cy, cw, ch ); + + AffineTransform tx = new AffineTransform(); + tx.translate( dx1 - sx1*scaleX, dy1 - sy1*scaleY ); + tx.scale( scaleX, scaleY ); + + boolean retval = drawImage(img, tx, bgcolor, observer); + setClip( oldClip ); + return retval; + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + ImageObserver observer) + { + return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, observer); + } + + /** + * Optimized method for drawing a CairoSurface onto this graphics context. + * + * @param surface The surface to draw. + * @param tx The transformation matrix (cannot be null). + * @param alpha The alpha value to paint with ( 0 <= alpha <= 1). + * @param interpolation The interpolation type. + */ + protected void drawCairoSurface(CairoSurface surface, AffineTransform tx, + double alpha, int interpolation) + { + // Find offset required if this surface is a sub-raster, and append offset + // to transformation. + if (surface.getSampleModelTranslateX() != 0 + || surface.getSampleModelTranslateY() != 0) + { + Point2D origin = new Point2D.Double(0, 0); + Point2D offset = new Point2D.Double(surface.getSampleModelTranslateX(), + surface.getSampleModelTranslateY()); + + tx.transform(origin, origin); + tx.transform(offset, offset); + + tx.translate(offset.getX() - origin.getX(), + offset.getY() - origin.getY()); + } + + // Find dimensions of this surface relative to the root parent surface + Rectangle bounds = new Rectangle(-surface.getSampleModelTranslateX(), + -surface.getSampleModelTranslateY(), + surface.width, surface.height); + + // Clip to the translated image + // We use direct cairo methods to avoid the overhead of maintaining a + // java copy of the clip, since we will be reverting it immediately + // after drawing + Shape newBounds = tx.createTransformedShape(bounds); + cairoSave(nativePointer); + walkPath(newBounds.getPathIterator(null), false); + cairoClip(nativePointer); + + // Draw the surface + try + { + double[] i2u = new double[6]; + tx.createInverse().getMatrix(i2u); + surface.nativeDrawSurface(surface.surfacePointer, nativePointer, i2u, + alpha, interpolation); + } + catch (NoninvertibleTransformException ex) + { + // This should never happen(?), so we don't need to do anything here. + ; + } + + // Restore clip + cairoRestore(nativePointer); + } + + + ///////////////////////// TEXT METHODS //////////////////////////////////// + + public void drawString(String str, float x, float y) + { + if (str == null || str.length() == 0) + return; + GdkFontPeer fontPeer = (GdkFontPeer) font.getPeer(); + TextLayout tl = (TextLayout) fontPeer.textLayoutCache.get(str); + if (tl == null) + { + tl = new TextLayout( str, getFont(), getFontRenderContext() ); + fontPeer.textLayoutCache.put(str, tl); + } + + // Set antialias to text_antialiasing, and set the ignoreAA flag so that + // the setting doesn't get overridden in a draw() or fill() call. + setAntialias(!hints.get(RenderingHints.KEY_TEXT_ANTIALIASING) + .equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)); + ignoreAA = true; + + tl.draw(this, x, y); + ignoreAA = false; + } + + public void drawString(String str, int x, int y) + { + drawString (str, (float) x, (float) y); + } + + public void drawString(AttributedCharacterIterator ci, int x, int y) + { + drawString (ci, (float) x, (float) y); + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + double alpha = 1.0; + + if( gv.getNumGlyphs() <= 0 ) + return; + + if (customPaint) + setCustomPaint(gv.getOutline().getBounds()); + + if (comp instanceof AlphaComposite) + alpha = ((AlphaComposite) comp).getAlpha(); + + setAntialias(!hints.get(RenderingHints.KEY_TEXT_ANTIALIASING) + .equals(RenderingHints.VALUE_TEXT_ANTIALIAS_OFF)); + ignoreAA = true; + + if (gv instanceof FreetypeGlyphVector && alpha == 1.0 + && !((FreetypeGlyphVector)gv).hasTransforms()) + { + int n = gv.getNumGlyphs (); + int[] codes = gv.getGlyphCodes (0, n, null); + long[] fontset = ((FreetypeGlyphVector)gv).getGlyphFonts (0, n, null); + float[] positions = gv.getGlyphPositions (0, n, null); + + setFont (gv.getFont ()); + GdkFontPeer fontPeer = (GdkFontPeer) font.getPeer(); + synchronized (fontPeer) + { + cairoDrawGlyphVector(nativePointer, fontPeer, + x, y, n, codes, positions, fontset); + } + } + else + { + translate(x, y); + fill(gv.getOutline()); + translate(-x, -y); + } + + ignoreAA = false; + } + + public void drawString(AttributedCharacterIterator ci, float x, float y) + { + GlyphVector gv = getFont().createGlyphVector(getFontRenderContext(), ci); + drawGlyphVector(gv, x, y); + } + + /** + * Should perhaps be contexct dependent, but this is left for now as an + * overloadable default implementation. + */ + public FontRenderContext getFontRenderContext() + { + return new FontRenderContext(transform, true, true); + } + + // Until such time as pango is happy to talk directly to cairo, we + // actually need to redirect some calls from the GtkFontPeer and + // GtkFontMetrics into the drawing kit and ask cairo ourselves. + + public FontMetrics getFontMetrics() + { + return getFontMetrics(getFont()); + } + + public FontMetrics getFontMetrics(Font f) + { + return ((GdkFontPeer) f.getPeer()).getFontMetrics(f); + } + + public void setFont(Font f) + { + // Sun's JDK does not throw NPEs, instead it leaves the current setting + // unchanged. So do we. + if (f == null) + return; + + if (f.getPeer() instanceof GdkFontPeer) + font = f; + else + font = + ((ClasspathToolkit)(Toolkit.getDefaultToolkit())) + .getFont(f.getName(), f.getAttributes()); + + GdkFontPeer fontpeer = (GdkFontPeer) getFont().getPeer(); + synchronized (fontpeer) + { + cairoSetFont(nativePointer, fontpeer); + } + } + + public Font getFont() + { + if (font == null) + return new Font("SansSerif", Font.PLAIN, 12); + return font; + } + + /////////////////////// MISC. PUBLIC METHODS ///////////////////////////////// + + public boolean hit(Rectangle rect, Shape s, boolean onStroke) + { + if( onStroke ) + { + Shape stroked = stroke.createStrokedShape( s ); + return stroked.intersects( (double)rect.x, (double)rect.y, + (double)rect.width, (double)rect.height ); + } + return s.intersects( (double)rect.x, (double)rect.y, + (double)rect.width, (double)rect.height ); + } + + public String toString() + { + return (getClass().getName() + + "[font=" + getFont().toString() + + ",color=" + fg.toString() + + "]"); + } + + ///////////////////////// PRIVATE METHODS /////////////////////////////////// + + /** + * All the drawImage() methods eventually get delegated here if the image + * is not a Cairo surface. + * + * @param bgcolor - if non-null draws the background color before + * drawing the image. + */ + private boolean drawRaster(ColorModel cm, Raster r, + AffineTransform imageToUser, Color bgcolor) + { + if (r == null) + return false; + + SampleModel sm = r.getSampleModel(); + DataBuffer db = r.getDataBuffer(); + + if (db == null || sm == null) + return false; + + if (cm == null) + cm = ColorModel.getRGBdefault(); + + double[] i2u = new double[6]; + if (imageToUser != null) + imageToUser.getMatrix(i2u); + else + { + i2u[0] = 1; + i2u[1] = 0; + i2u[2] = 0; + i2u[3] = 1; + i2u[4] = 0; + i2u[5] = 0; + } + + int[] pixels = findSimpleIntegerArray(cm, r); + + if (pixels == null) + { + // FIXME: I don't think this code will work correctly with a non-RGB + // MultiPixelPackedSampleModel. Although this entire method should + // probably be rewritten to better utilize Cairo's different supported + // data formats. + if (sm instanceof MultiPixelPackedSampleModel) + { + pixels = r.getPixels(0, 0, r.getWidth(), r.getHeight(), pixels); + for (int i = 0; i < pixels.length; i++) + pixels[i] = cm.getRGB(pixels[i]); + } + else + { + pixels = new int[r.getWidth() * r.getHeight()]; + for (int i = 0; i < pixels.length; i++) + pixels[i] = cm.getRGB(db.getElem(i)); + } + } + + // Change all transparent pixels in the image to the specified bgcolor, + // or (if there's no alpha) fill in an alpha channel so that it paints + // correctly. + if (cm.hasAlpha()) + { + if (bgcolor != null && cm.hasAlpha()) + for (int i = 0; i < pixels.length; i++) + { + if (cm.getAlpha(pixels[i]) == 0) + pixels[i] = bgcolor.getRGB(); + } + } + else + for (int i = 0; i < pixels.length; i++) + pixels[i] |= 0xFF000000; + + double alpha = 1.0; + if (comp instanceof AlphaComposite) + alpha = ((AlphaComposite) comp).getAlpha(); + + drawPixels(nativePointer, pixels, r.getWidth(), r.getHeight(), + r.getWidth(), i2u, alpha, getInterpolation()); + + // Cairo seems to lose the current color which must be restored. + updateColor(); + + return true; + } + + /** + * Shifts an x-coordinate by 0.5 in device space. + */ + private double shiftX(double coord, boolean doShift) + { + if (doShift) + { + double shift = 0.5; + if (!transform.isIdentity()) + shift /= transform.getScaleX(); + return (coord + shift); + } + else + return coord; + } + + /** + * Shifts a y-coordinate by 0.5 in device space. + */ + private double shiftY(double coord, boolean doShift) + { + if (doShift) + { + double shift = 0.5; + if (!transform.isIdentity()) + shift /= transform.getScaleY(); + return (coord + shift); + } + else + return coord; + } + + /** + * Adds a pathIterator to the current Cairo path, also sets the cairo winding rule. + */ + private void walkPath(PathIterator p, boolean doShift) + { + double x = 0; + double y = 0; + double[] coords = new double[6]; + + cairoSetFillRule(nativePointer, p.getWindingRule()); + for (; ! p.isDone(); p.next()) + { + int seg = p.currentSegment(coords); + switch (seg) + { + case PathIterator.SEG_MOVETO: + x = shiftX(coords[0], doShift); + y = shiftY(coords[1], doShift); + cairoMoveTo(nativePointer, x, y); + break; + case PathIterator.SEG_LINETO: + x = shiftX(coords[0], doShift); + y = shiftY(coords[1], doShift); + cairoLineTo(nativePointer, x, y); + break; + case PathIterator.SEG_QUADTO: + // splitting a quadratic bezier into a cubic: + // see: http://pfaedit.sourceforge.net/bezier.html + double x1 = x + (2.0 / 3.0) * (shiftX(coords[0], doShift) - x); + double y1 = y + (2.0 / 3.0) * (shiftY(coords[1], doShift) - y); + + double x2 = x1 + (1.0 / 3.0) * (shiftX(coords[2], doShift) - x); + double y2 = y1 + (1.0 / 3.0) * (shiftY(coords[3], doShift) - y); + + x = shiftX(coords[2], doShift); + y = shiftY(coords[3], doShift); + cairoCurveTo(nativePointer, x1, y1, x2, y2, x, y); + break; + case PathIterator.SEG_CUBICTO: + x = shiftX(coords[4], doShift); + y = shiftY(coords[5], doShift); + cairoCurveTo(nativePointer, shiftX(coords[0], doShift), + shiftY(coords[1], doShift), + shiftX(coords[2], doShift), + shiftY(coords[3], doShift), x, y); + break; + case PathIterator.SEG_CLOSE: + cairoClosePath(nativePointer); + break; + } + } + } + + /** + * Used by setRenderingHints() + */ + private Map getDefaultHints() + { + HashMap defaultHints = + new HashMap(); + + defaultHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_DEFAULT); + + defaultHints.put(RenderingHints.KEY_STROKE_CONTROL, + RenderingHints.VALUE_STROKE_DEFAULT); + + defaultHints.put(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_OFF); + + defaultHints.put(RenderingHints.KEY_ANTIALIASING, + RenderingHints.VALUE_ANTIALIAS_OFF); + + defaultHints.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_DEFAULT); + + return defaultHints; + } + + /** + * Used by drawRaster and GdkPixbufDecoder + */ + public static int[] findSimpleIntegerArray (ColorModel cm, Raster raster) + { + if (cm == null || raster == null) + return null; + + if (! cm.getColorSpace().isCS_sRGB()) + return null; + + if (! (cm instanceof DirectColorModel)) + return null; + + DirectColorModel dcm = (DirectColorModel) cm; + + if (dcm.getRedMask() != 0x00FF0000 || dcm.getGreenMask() != 0x0000FF00 + || dcm.getBlueMask() != 0x000000FF) + return null; + + if (! (raster instanceof WritableRaster)) + return null; + + if (raster.getSampleModel().getDataType() != DataBuffer.TYPE_INT) + return null; + + if (! (raster.getDataBuffer() instanceof DataBufferInt)) + return null; + + DataBufferInt db = (DataBufferInt) raster.getDataBuffer(); + + if (db.getNumBanks() != 1) + return null; + + // Finally, we have determined that this is a single bank, [A]RGB-int + // buffer in sRGB space. It's worth checking all this, because it means + // that cairo can paint directly into the data buffer, which is very + // fast compared to all the normal copying and converting. + + return db.getData(); + } + + /** + * Helper method to transform the clip. This is called by the various + * transformation-manipulation methods to update the clip (which is in + * userspace) accordingly. + * + * The transform usually is the inverse transform that was applied to the + * graphics object. + * + * @param t the transform to apply to the clip + */ + private void updateClip(AffineTransform t) + { + if (clip == null) + return; + + // If the clip is a rectangle, and the transformation preserves the shape + // (translate/stretch only), then keep the clip as a rectangle + double[] matrix = new double[4]; + t.getMatrix(matrix); + if (clip instanceof Rectangle2D && matrix[1] == 0 && matrix[2] == 0) + { + Rectangle2D rect = (Rectangle2D)clip; + double[] origin = new double[] {rect.getX(), rect.getY()}; + double[] dimensions = new double[] {rect.getWidth(), rect.getHeight()}; + t.transform(origin, 0, origin, 0, 1); + t.deltaTransform(dimensions, 0, dimensions, 0, 1); + rect.setRect(origin[0], origin[1], dimensions[0], dimensions[1]); + } + else + { + if (! (clip instanceof GeneralPath)) + clip = new GeneralPath(clip); + + GeneralPath p = (GeneralPath) clip; + p.transform(t); + } + } + + private static Rectangle computeIntersection(int x, int y, int w, int h, + Rectangle rect) + { + int x2 = rect.x; + int y2 = rect.y; + int w2 = rect.width; + int h2 = rect.height; + + int dx = (x > x2) ? x : x2; + int dy = (y > y2) ? y : y2; + int dw = (x + w < x2 + w2) ? (x + w - dx) : (x2 + w2 - dx); + int dh = (y + h < y2 + h2) ? (y + h - dy) : (y2 + h2 - dy); + + if (dw >= 0 && dh >= 0) + rect.setBounds(dx, dy, dw, dh); + else + rect.setBounds(0, 0, 0, 0); + + return rect; + } + + static Rectangle2D getTransformedBounds(Rectangle2D bounds, AffineTransform tx) + { + double x1 = bounds.getX(); + double x2 = bounds.getX() + bounds.getWidth(); + double x3 = x1; + double x4 = x2; + double y1 = bounds.getY(); + double y2 = y1; + double y3 = bounds.getY() + bounds.getHeight(); + double y4 = y3; + + double[] points = new double[] {x1, y1, x2, y2, x3, y3, x4, y4}; + tx.transform(points, 0, points, 0, 4); + + double minX = points[0]; + double maxX = minX; + double minY = points[1]; + double maxY = minY; + for (int i = 0; i < 8; i++) + { + if (points[i] < minX) + minX = points[i]; + if (points[i] > maxX) + maxX = points[i]; + i++; + + if (points[i] < minY) + minY = points[i]; + if (points[i] > maxY) + maxY = points[i]; + } + + return new Rectangle2D.Double(minX, minY, (maxX - minX), (maxY - minY)); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java new file mode 100644 index 000000000..71f6638e4 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurface.java @@ -0,0 +1,428 @@ +/* CairoSurface.java + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import gnu.java.awt.Buffers; + +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DataBufferInt; +import java.awt.image.DirectColorModel; +import java.awt.image.Raster; +import java.awt.image.RasterFormatException; +import java.awt.image.SampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.WritableRaster; +import java.nio.ByteOrder; +import java.util.Arrays; +import java.util.Hashtable; + +/** + * CairoSurface - wraps a Cairo surface. + * + * @author Sven de Marothy + */ +public class CairoSurface extends WritableRaster +{ + int width = -1, height = -1; + + /** + * The native pointer to the Cairo surface. + */ + long surfacePointer; + + /** + * Whether the data buffer is shared between java and cairo. + */ + boolean sharedBuffer; + + // FIXME: use only the cairoCM_pre colormodel + // since that's what Cairo really uses (is there a way to do this cheaply? + // we use a non-multiplied model most of the time to avoid costly coercion + // operations...) + static ColorModel cairoColorModel = new DirectColorModel(32, 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000); + + static ColorModel cairoCM_pre = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), + 32, 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000, + true, + Buffers.smallestAppropriateTransferType(32)); + + // This CM corresponds to the CAIRO_FORMAT_RGB24 type in Cairo + static ColorModel cairoCM_opaque = new DirectColorModel(24, 0x00FF0000, + 0x0000FF00, + 0x000000FF); + /** + * Allocates and clears the buffer and creates the cairo surface. + * @param width - the image size + * @param height - the image size + * @param stride - the buffer row stride. (in ints) + */ + private native void create(int width, int height, int stride, int[] buf); + + /** + * Destroys the cairo surface and frees the buffer. + */ + private native void destroy(long surfacePointer, int[] buf); + + /** + * Draws this image to a given CairoGraphics context, + * with an affine transform given by i2u. + */ + public native void nativeDrawSurface(long surfacePointer, long contextPointer, + double[] i2u, double alpha, + int interpolation); + + /** + * Synchronizes the image's data buffers, copying any changes made in the + * Java array into the native array. + * + * This method should only be called if (sharedBuffers == false). + */ + native void syncNativeToJava(long surfacePointer, int[] buffer); + + /** + * Synchronizes the image's data buffers, copying any changes made in the + * native array into the Java array. + * + * This method should only be called if (sharedBuffers == false). + */ + native void syncJavaToNative(long surfacePointer, int[] buffer); + + /** + * Return the buffer, with the sample values of each pixel reversed + * (ie, in ABGR instead of ARGB). + * + * @return A pointer to a flipped buffer. The memory is allocated in native + * code, and must be explicitly freed when it is no longer needed. + */ + native long getFlippedBuffer(long surfacePointer); + + /** + * Create a cairo_surface_t with specified width and height. + * The format will be ARGB32 with premultiplied alpha and native bit + * and word ordering. + */ + public CairoSurface(int width, int height) + { + this(0, 0, width, height); + } + + public CairoSurface(int x, int y, int width, int height) + { + super(createCairoSampleModel(width, height), null, new Point(x, y)); + + if(width <= 0 || height <= 0) + throw new IllegalArgumentException("Image must be at least 1x1 pixels."); + + this.width = width; + this.height = height; + dataBuffer = new DataBufferInt(width * height); + create(width, height, width, getData()); + + if(surfacePointer == 0) + throw new Error("Could not allocate bitmap."); + } + + /** + * Create a Cairo Surface that is a subimage of another Cairo Surface + */ + public CairoSurface(SampleModel sm, CairoSurface parent, Rectangle bounds, + Point origin) + { + super(sm, parent.dataBuffer, bounds, origin, parent); + + this.width = super.width; + this.height = super.height; + this.surfacePointer = parent.surfacePointer; + this.sharedBuffer = parent.sharedBuffer; + this.dataBuffer = parent.dataBuffer; + } + + /** + * Create a cairo_surface_t from a GtkImage instance. + * (data is copied, not shared) + */ + CairoSurface(GtkImage image) + { + this(image.width, image.height); + + // Copy the pixel data from the GtkImage. + int[] data = image.getPixels(); + + // Swap ordering from GdkPixbuf to Cairo + if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) + { + for (int i = 0; i < data.length; i++ ) + { + // On a big endian system we get a RRGGBBAA data array. + int alpha = data[i] & 0xFF; + if( alpha == 0 ) // I do not know why we need this, but it works. + data[i] = 0; + else + { + // Cairo needs a ARGB32 native array. + data[i] = (data[i] >>> 8) | (alpha << 24); + } + } + } + else + { + for (int i = 0; i < data.length; i++ ) + { + // On a little endian system we get a AABBGGRR data array. + int alpha = data[i] & 0xFF000000; + if( alpha == 0 ) // I do not know why we need this, but it works. + data[i] = 0; + else + { + int b = (data[i] & 0xFF0000) >> 16; + int g = (data[i] & 0xFF00); + int r = (data[i] & 0xFF) << 16; + // Cairo needs a ARGB32 native array. + data[i] = alpha | r | g | b; + } + } + } + + System.arraycopy(data, 0, getData(), 0, data.length); + } + + /** + * Dispose of the native data. + */ + public void dispose() + { + if(surfacePointer != 0 && parent == null) + destroy(surfacePointer, getData()); + } + + /** + * Call dispose() to clean up any native resources allocated. + */ + protected void finalize() + { + dispose(); + } + + /** + * Return a GtkImage from this Cairo surface. + */ + public GtkImage getGtkImage() + { + return new GtkImage(width, height, getFlippedBuffer(surfacePointer)); + } + + /** + * Convenience method to quickly grab the data array backing this Raster. + * + * @return The array behind the databuffer. + */ + public int[] getData() + { + return ((DataBufferInt)dataBuffer).getData(); + } + + /** + * Returns a BufferedImage backed by a Cairo surface. + */ + public static BufferedImage getBufferedImage(int width, int height) + { + return getBufferedImage(new CairoSurface(width, height)); + } + + /** + * Returns a BufferedImage backed by a Cairo surface, + * created from a GtkImage. + */ + public static BufferedImage getBufferedImage(GtkImage image) + { + return getBufferedImage(new CairoSurface(image)); + } + + /** + * Returns a BufferedImage backed by a Cairo surface. + */ + public static BufferedImage getBufferedImage(CairoSurface surface) + { + return new BufferedImage(cairoColorModel, surface, + cairoColorModel.isAlphaPremultiplied(), + new Hashtable()); + } + + /** + * Return a Graphics2D drawing to the CairoSurface. + */ + public Graphics2D getGraphics() + { + return new CairoSurfaceGraphics(this); + } + + ///// Methods used by CairoSurfaceGraphics ///// + /** + * Creates a cairo_t drawing context, returns the pointer as a long. + * Used by CairoSurfaceGraphics. + */ + native long nativeNewCairoContext(long surfacePointer); + + public long newCairoContext() + { + return nativeNewCairoContext(surfacePointer); + } + + /** + * Copy a portion of this surface to another area on the surface. The given + * parameters must be within bounds - count on a segfault otherwise. + * + * @param x The x coordinate of the area to be copied from. + * @param y The y coordinate of the area to be copied from. + * @param width The width of the area to be copied. + * @param height The height of the area to be copied. + * @param dx The destination x coordinate. + * @param dy The destination y coordinate. + * @param stride The scanline stride. + */ + public void copyAreaNative(int x, int y, int width, + int height, int dx, int dy, int stride) + { + copyAreaNative2(surfacePointer, x, y, width, height, dx, dy, stride); + } + native void copyAreaNative2(long surfacePointer, + int x, int y, int width, int height, + int dx, int dy, int stride); + + /** + * Creates a SampleModel that matches Cairo's native format + */ + protected static SampleModel createCairoSampleModel(int w, int h) + { + return new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, w, h, + new int[]{0x00FF0000, 0x0000FF00, + 0x000000FF, 0xFF000000}); + } + + /** + * Returns whether this ColorModel is compatible with Cairo's native types. + * + * @param cm The color model to check. + * @return Whether it is compatible. + */ + public static boolean isCompatibleColorModel(ColorModel cm) + { + return (cm.equals(cairoCM_pre) || cm.equals(cairoCM_opaque) || + cm.equals(cairoColorModel)); + } + + /** + * Returns whether this SampleModel is compatible with Cairo's native types. + * + * @param sm The sample model to check. + * @return Whether it is compatible. + */ + public static boolean isCompatibleSampleModel(SampleModel sm) + { + return (sm instanceof SinglePixelPackedSampleModel + && sm.getDataType() == DataBuffer.TYPE_INT + && Arrays.equals(((SinglePixelPackedSampleModel)sm).getBitMasks(), + new int[]{0x00FF0000, 0x0000FF00, + 0x000000FF, 0xFF000000})); + } + + ///// Methods interhited from Raster and WritableRaster ///// + public Raster createChild(int parentX, int parentY, int width, int height, + int childMinX, int childMinY, int[] bandList) + { + return createWritableChild(parentX, parentY, width, height, + childMinX, childMinY, bandList); + } + + public WritableRaster createCompatibleWritableRaster() + { + return new CairoSurface(width, height); + } + + public WritableRaster createCompatibleWritableRaster (int x, int y, + int w, int h) + { + return new CairoSurface(x, y, w, h); + } + + public Raster createTranslatedChild(int childMinX, int childMinY) + { + return createWritableTranslatedChild(childMinX, childMinY); + } + + public WritableRaster createWritableChild(int parentX, int parentY, + int w, int h, int childMinX, + int childMinY, int[] bandList) + { + if (parentX < minX || parentX + w > minX + width + || parentY < minY || parentY + h > minY + height) + throw new RasterFormatException("Child raster extends beyond parent"); + + SampleModel sm = (bandList == null) ? + sampleModel : + sampleModel.createSubsetSampleModel(bandList); + + return new CairoSurface(sm, this, + new Rectangle(childMinX, childMinY, w, h), + new Point(sampleModelTranslateX + childMinX - parentX, + sampleModelTranslateY + childMinY - parentY)); + } + + public WritableRaster createWritableTranslatedChild(int x, int y) + { + int tcx = sampleModelTranslateX - minX + x; + int tcy = sampleModelTranslateY - minY + y; + + return new CairoSurface(sampleModel, this, + new Rectangle(x, y, width, height), + new Point(tcx, tcy)); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java new file mode 100644 index 000000000..a0c6caa9a --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/CairoSurfaceGraphics.java @@ -0,0 +1,355 @@ +/* CairoSurfaceGraphics.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.RenderedImage; +import java.util.Hashtable; + +/** + * Implementation of Graphics2D on a Cairo surface. + */ +public class CairoSurfaceGraphics extends CairoGraphics2D +{ + protected CairoSurface surface; + private BufferedImage buffer; + private long cairo_t; + + /** + * Create a graphics context from a cairo surface + */ + public CairoSurfaceGraphics(CairoSurface surface) + { + this.surface = surface; + cairo_t = surface.newCairoContext(); + setup( cairo_t ); + setClip(0, 0, surface.width, surface.height); + } + + /** + * Creates another context from a surface. + * Used by create(). + */ + private CairoSurfaceGraphics(CairoSurfaceGraphics copyFrom) + { + surface = copyFrom.surface; + cairo_t = surface.newCairoContext(); + copy( copyFrom, cairo_t ); + } + + public Graphics create() + { + return new CairoSurfaceGraphics(this); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); + } + + protected Rectangle2D getRealBounds() + { + return new Rectangle2D.Double(0.0, 0.0, surface.width, surface.height); + } + + public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy) + { + surface.copyAreaNative(x, y, width, height, dx, dy, surface.width); + } + + /** + * Overloaded methods that do actual drawing need to account for custom + * composites + */ + public void draw(Shape s) + { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + + // Find total bounds of shape + Rectangle r = findStrokedBounds(s); + if (shiftDrawCalls) + { + r.width++; + r.height++; + } + + // Do the drawing + if (comp == null || comp instanceof AlphaComposite) + super.draw(s); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setStroke(this.getStroke()); + g2d.setColor(this.getColor()); + g2d.setTransform(transform); + g2d.draw(s); + + drawComposite(r.getBounds2D(), null); + } + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); + } + + public void fill(Shape s) + { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + + if (comp == null || comp instanceof AlphaComposite) + super.fill(s); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setColor(this.getColor()); + g2d.setTransform(transform); + g2d.fill(s); + + drawComposite(s.getBounds2D(), null); + } + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + + if (comp == null || comp instanceof AlphaComposite) + super.drawRenderedImage(image, xform); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.setTransform(transform); + g2d.drawRenderedImage(image, xform); + + drawComposite(buffer.getRaster().getBounds(), null); + } + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); + } + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + + boolean ret; + if (comp == null || comp instanceof AlphaComposite) + ret = super.drawImage(img, xform, bgcolor, obs); + + else + { + // Get buffered image of source + if( !(img instanceof BufferedImage) ) + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + img = Toolkit.getDefaultToolkit().createImage(source); + } + BufferedImage bImg = (BufferedImage) img; + + // Find translated bounds + Rectangle2D bounds = new Rectangle(bImg.getMinX(), bImg.getMinY(), + bImg.getWidth(), bImg.getHeight()); + if (xform != null) + bounds = getTransformedBounds(bounds, xform); + + // Create buffer and draw image + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.drawImage(img, xform, obs); + + // Perform compositing + ret = drawComposite(bounds, obs); + } + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); + + return ret; + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + if (!surface.sharedBuffer) + surface.syncJavaToNative(surface.surfacePointer, surface.getData()); + + if (comp == null || comp instanceof AlphaComposite) + super.drawGlyphVector(gv, x, y); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setStroke(this.getStroke()); + g2d.drawGlyphVector(gv, x, y); + + Rectangle2D bounds = gv.getLogicalBounds(); + bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(), + bounds.getWidth(), bounds.getHeight()); + drawComposite(bounds, null); + } + + if (!surface.sharedBuffer) + surface.syncNativeToJava(surface.surfacePointer, surface.getData()); + } + + private boolean drawComposite(Rectangle2D bounds, ImageObserver observer) + { + // Find bounds in device space + bounds = getTransformedBounds(bounds, transform); + + // Clip bounds by the stored clip, and by the internal buffer + Rectangle2D devClip = this.getClipInDevSpace(); + Rectangle2D.intersect(bounds, devClip, bounds); + devClip = new Rectangle(buffer.getMinX(), buffer.getMinY(), + buffer.getWidth(), buffer.getHeight()); + Rectangle2D.intersect(bounds, devClip, bounds); + + // Round bounds as needed, but be careful in our rounding + // (otherwise it may leave unpainted stripes) + double x = bounds.getX(); + double y = bounds.getY(); + double maxX = x + bounds.getWidth(); + double maxY = y + bounds.getHeight(); + x = Math.round(x); + y = Math.round(y); + bounds.setRect(x, y, Math.round(maxX - x), Math.round(maxY - y)); + + // Find subimage of internal buffer for updating + BufferedImage buffer2 = buffer; + if (!bounds.equals(buffer2.getRaster().getBounds())) + buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), + (int)bounds.getHeight()); + + // Find subimage of main image for updating + BufferedImage current = CairoSurface.getBufferedImage(surface); + current = current.getSubimage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), + (int)bounds.getHeight()); + + // Perform actual composite operation + compCtx.compose(buffer2.getRaster(), current.getRaster(), + buffer2.getRaster()); + + // Set cairo's composite to direct SRC, since we've already done our own + // compositing + Composite oldcomp = comp; + setComposite(AlphaComposite.Src); + + // This MUST call directly into the "action" method in CairoGraphics2D, + // not one of the wrappers, to ensure that the composite isn't processed + // more than once! + boolean rv = super.drawImage(buffer2, + AffineTransform.getTranslateInstance(bounds.getX(), + bounds.getY()), + null, null); + setComposite(oldcomp); + updateColor(); + return rv; + } + + private void createBuffer() + { + if (buffer == null) + { + buffer = new BufferedImage(getBufferCM(), + surface.createCompatibleWritableRaster(), + getBufferCM().isAlphaPremultiplied(), + new Hashtable()); + } + else + { + Graphics2D g2d = ((Graphics2D)buffer.getGraphics()); + + g2d.setBackground(new Color(0,0,0,0)); + g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight()); + } + } + + protected ColorModel getNativeCM() + { + return CairoSurface.cairoCM_pre; + } + + protected ColorModel getBufferCM() + { + return CairoSurface.cairoColorModel; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java new file mode 100644 index 000000000..50161b2b7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphics.java @@ -0,0 +1,941 @@ +/* ComponentGraphics.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import gnu.classpath.Pointer; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.WritableRaster; +import java.util.Hashtable; + +/** + * ComponentGraphics - context for drawing directly to a component, + * as this is an X drawable, it requires that we use GTK locks. + * + * This context draws directly to the drawable and requires xrender. + */ +public class ComponentGraphics extends CairoGraphics2D +{ + private static final boolean hasXRenderExtension = hasXRender(); + + private GtkComponentPeer component; + protected long cairo_t; + private BufferedImage buffer, componentBuffer; + + private static ThreadLocal hasLock = new ThreadLocal(); + private static Integer ONE = Integer.valueOf(1); + + ComponentGraphics() + { + } + + private ComponentGraphics(GtkComponentPeer component) + { + this.component = component; + cairo_t = initState(component); + setup( cairo_t ); + Rectangle bounds = component.awtComponent.getBounds(); + setClip( new Rectangle( 0, 0, bounds.width, bounds.height) ); + setBackground(component.awtComponent.getBackground()); + setColor(component.awtComponent.getForeground()); + } + + private ComponentGraphics(ComponentGraphics cg) + { + component = cg.component; + cairo_t = initState(component); + copy( cg, cairo_t ); + Rectangle bounds = component.awtComponent.getBounds(); + setClip( new Rectangle( 0, 0, bounds.width, bounds.height) ); + setBackground(component.awtComponent.getBackground()); + setColor(component.awtComponent.getForeground()); + } + + /** + * Creates a cairo_t for the component surface and return it. + */ + private native long initState(GtkComponentPeer component); + + /** + * Obtain and hold a GDK lock, which is required for all drawing operations + * in this graphics context (since it is backed by an X surface). + * + * This method causes the GDK locking behaviour to be re-entrant. No race + * conditions are caused since a ThreadLocal is used and each thread has its + * own lock counter. + */ + private void lock() + { + Integer i = hasLock.get(); + if (i == null) + { + start_gdk_drawing(); + hasLock.set(ONE); + } + else + hasLock.set(Integer.valueOf(i.intValue() + 1)); + } + + /** + * Release the re-entrant GDK lock. + */ + private void unlock() + { + Integer i = hasLock.get(); + if (i == null) + throw new IllegalStateException(); + if (i == ONE) + { + hasLock.set(null); + end_gdk_drawing(); + } + else if (i.intValue() == 2) + hasLock.set(ONE); + else + hasLock.set(Integer.valueOf(i.intValue() - 1)); + } + + /** + * Creates a cairo_t for a volatile image + */ + protected native long initFromVolatile( long pixmapPtr); + + /** + * Grab lock + */ + private native void start_gdk_drawing(); + + /** + * Release lock + */ + private native void end_gdk_drawing(); + + /** + * Query if the system has the XRender extension. + */ + public static native boolean hasXRender(); + + /** + * This is a utility method (used by GtkComponentPeer) for grabbing the + * image of a component. + */ + private static native Pointer nativeGrab(GtkComponentPeer component); + + private native void copyAreaNative(GtkComponentPeer component, int x, int y, + int width, int height, int dx, int dy); + + private native void drawVolatile(GtkComponentPeer component, + long vimg, int x, int y, + int width, int height, int cx, int cy, + int cw, int ch); + + /** + * Not really related (moveme?). Utility method used by GtkComponent. + */ + public static GtkImage grab( GtkComponentPeer component ) + { + return new GtkImage( nativeGrab( component ) ); + } + + /** + * Returns a Graphics2D object for a component, either an instance of this + * class (if xrender is supported), or a context which copies. + */ + public static Graphics2D getComponentGraphics(GtkComponentPeer component) + { + if( hasXRenderExtension ) + return new ComponentGraphics(component); + + Rectangle r = component.awtComponent.getBounds(); + return new ComponentGraphicsCopy(r.width, r.height, component); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + return component.getGraphicsConfiguration(); + } + + public Graphics create() + { + return new ComponentGraphics(this); + } + + protected Rectangle2D getRealBounds() + { + return component.awtComponent.getBounds(); + } + + public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy) + { + copyAreaNative(component, x, y, width, height, dx, dy); + } + + /** + * Overloaded methods that do actual drawing need to enter the gdk threads + * and also do certain things before and after. + */ + public void draw(Shape s) + { + if (comp == null || comp instanceof AlphaComposite) + super.draw(s); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setStroke(this.getStroke()); + g2d.setColor(this.getColor()); + g2d.draw(s); + + drawComposite(s.getBounds2D(), null); + } + } + + public void fill(Shape s) + { + if (comp == null || comp instanceof AlphaComposite) + super.fill(s); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setColor(this.getColor()); + g2d.fill(s); + + drawComposite(s.getBounds2D(), null); + } + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + if (comp == null || comp instanceof AlphaComposite) + super.drawRenderedImage(image, xform); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.drawRenderedImage(image, xform); + + drawComposite(buffer.getRaster().getBounds(), null); + } + } + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + boolean rv; + if (comp == null || comp instanceof AlphaComposite) + rv = super.drawImage(img, xform, bgcolor, obs); + + else + { + // Get buffered image of source + if( !(img instanceof BufferedImage) ) + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + img = Toolkit.getDefaultToolkit().createImage(source); + } + BufferedImage bImg = (BufferedImage) img; + + // Find translated bounds + Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY()); + Point2D pt = new Point2D.Double(bImg.getWidth() + bImg.getMinX(), + bImg.getHeight() + bImg.getMinY()); + if (xform != null) + { + origin = xform.transform(origin, origin); + pt = xform.transform(pt, pt); + } + + // Create buffer and draw image + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.drawImage(img, xform, obs); + + // Perform compositing + rv = drawComposite(new Rectangle2D.Double(origin.getX(), + origin.getY(), + pt.getX(), pt.getY()), + obs); + } + return rv; + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + if (comp == null || comp instanceof AlphaComposite) + super.drawGlyphVector(gv, x, y); + + else + { + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setStroke(this.getStroke()); + g2d.drawGlyphVector(gv, x, y); + + Rectangle2D bounds = gv.getLogicalBounds(); + bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(), + bounds.getWidth(), bounds.getHeight()); + drawComposite(bounds, null); + } + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + // If it is a GtkVolatileImage with an "easy" transform then + // draw directly. Always pass a BufferedImage to super to avoid + // deadlock (see Note in CairoGraphics.drawImage()). + if (img instanceof GtkVolatileImage) + { + GtkVolatileImage vimg = (GtkVolatileImage) img; + int type = transform.getType(); + if ((type == AffineTransform.TYPE_IDENTITY + || type == AffineTransform.TYPE_TRANSLATION) + && (clip == null || clip instanceof Rectangle2D)) + { + Rectangle2D r = (Rectangle2D) clip; + if (r == null) + r = getRealBounds(); + x += transform.getTranslateX(); + y += transform.getTranslateY(); + drawVolatile(component, vimg.nativePointer, + x, y, vimg.width, vimg.height, + (int) (r.getX() + transform.getTranslateX()), + (int) (r.getY() + transform.getTranslateY()), + (int) r.getWidth(), + (int) r.getHeight()); + return true; + } + else + return super.drawImage(vimg.getSnapshot(), x, y, observer); + } + + BufferedImage bimg; + if (img instanceof BufferedImage) + bimg = (BufferedImage) img; + else + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + bimg = (BufferedImage) Toolkit.getDefaultToolkit().createImage(source); + } + return super.drawImage(bimg, x, y, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) + { + // If it is a GtkVolatileImage with an "easy" transform then + // draw directly. Always pass a BufferedImage to super to avoid + // deadlock (see Note in CairoGraphics.drawImage()). + if (img instanceof GtkVolatileImage + && (clip == null || clip instanceof Rectangle2D)) + { + GtkVolatileImage vimg = (GtkVolatileImage) img; + int type = transform.getType(); + if ((type == AffineTransform.TYPE_IDENTITY + || type == AffineTransform.TYPE_TRANSLATION) + && (clip == null || clip instanceof Rectangle2D)) + { + Rectangle2D r = (Rectangle2D) clip; + if (r == null) + r = getRealBounds(); + x += transform.getTranslateX(); + y += transform.getTranslateY(); + drawVolatile(component, vimg.nativePointer, + x, y, width, height, + (int) (r.getX() + transform.getTranslateX()), + (int) (r.getY() + transform.getTranslateY()), + (int) r.getWidth(), + (int) r.getHeight()); + return true; + } + else + return super.drawImage(vimg.getSnapshot(), x, y, + width, height, observer); + } + + BufferedImage bimg; + img = AsyncImage.realImage(img, observer); + if (img instanceof BufferedImage) + bimg = (BufferedImage) img; + else + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + bimg = (BufferedImage) Toolkit.getDefaultToolkit().createImage(source); + } + return super.drawImage(bimg, x, y, width, height, observer); + } + + private boolean drawComposite(Rectangle2D bounds, ImageObserver observer) + { + // Clip source to visible areas that need updating + Rectangle2D clip = this.getClipBounds(); + Rectangle2D.intersect(bounds, clip, bounds); + clip = new Rectangle(buffer.getMinX(), buffer.getMinY(), + buffer.getWidth(), buffer.getHeight()); + Rectangle2D.intersect(bounds, clip, bounds); + + BufferedImage buffer2 = buffer; + if (!bounds.equals(buffer2.getRaster().getBounds())) + buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), + (int)bounds.getHeight()); + + // Get destination clip to bounds + double[] points = new double[] {bounds.getX(), bounds.getY(), + bounds.getMaxX(), bounds.getMaxY()}; + transform.transform(points, 0, points, 0, 2); + + Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1], + points[2] - points[0], + points[3] - points[1]); + + Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds); + + // Get current image on the component + GtkImage img = grab(component); + Graphics gr = componentBuffer.createGraphics(); + gr.drawImage(img, 0, 0, null); + gr.dispose(); + + BufferedImage cBuffer = componentBuffer; + if (!deviceBounds.equals(cBuffer.getRaster().getBounds())) + cBuffer = cBuffer.getSubimage((int)deviceBounds.getX(), + (int)deviceBounds.getY(), + (int)deviceBounds.getWidth(), + (int)deviceBounds.getHeight()); + + // Perform actual composite operation + compCtx.compose(buffer2.getRaster(), cBuffer.getRaster(), + cBuffer.getRaster()); + + // This MUST call directly into the "action" method in CairoGraphics2D, + // not one of the wrappers, to ensure that the composite isn't processed + // more than once! + boolean rv = super.drawImage(cBuffer, + AffineTransform.getTranslateInstance(bounds.getX(), + bounds.getY()), + null, null); + return rv; + } + + private void createBuffer() + { + if (buffer == null) + { + WritableRaster rst; + rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(), + component.awtComponent.getHeight()), + new Point(0,0)); + + buffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst, + GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(), + new Hashtable()); + } + else + { + Graphics2D g2d = ((Graphics2D)buffer.getGraphics()); + + g2d.setBackground(new Color(0,0,0,0)); + g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight()); + } + + if (componentBuffer == null) + { + WritableRaster rst; + rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(component.awtComponent.getWidth(), + component.awtComponent.getHeight()), + new Point(0,0)); + + componentBuffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst, + GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(), + new Hashtable()); + } + } + + protected ColorModel getNativeCM() + { + return GtkVolatileImage.gdkColorModel; + } + + /* --- START OVERRIDDEN NATIVE METHODS ---- + * All native methods in CairoGraphics2D should be overridden here and + * enclosed in locks, since the cairo surface is backed by an X surface + * in this graphics context and the X surface requires external locking. + * + * We lock everything "just in case", since it's difficult to know which + * calls are and aren't thread-safe. Overriding and locking the native + * methods allows superclass code in CairoGraphics2D to execute properly, + * without the need to override every single method. + * + * CAVEAT: if native code obtains a lock (using gdk_threads_enter(), not the + * lock() method provided here) and then calls back into Java and one of these + * methods ends up being called, we will deadlock. The lock is only reentrant + * when called via our lock() method. + */ + + /* These methods are already locked in the superclass CairoGraphics2D + * so they do not need to be overridden: + * + * public void disposeNative + * + * protected void cairoDrawGlyphVector + * + * protected void cairoSetFont + */ + + @Override + protected long init(long pointer) + { + long ret; + + try + { + lock(); + ret = super.init(pointer); + } + finally + { + unlock(); + } + + return ret; + } + + @Override + protected void drawPixels(long pointer, int[] pixels, int w, int h, + int stride, double[] i2u, double alpha, + int interpolation) + { + try + { + lock(); + super.drawPixels(pointer, pixels, w, h, stride, i2u, alpha, + interpolation); + } + finally + { + unlock(); + } + } + + @Override + protected void setGradient(long pointer, double x1, double y1, + double x2, double y2, + int r1, int g1, int b1, int a1, + int r2, int g2, int b2, int a2, boolean cyclic) + { + try + { + lock(); + super.setGradient(pointer, x1, y1, x2, y2, r1, g1, b1, a1, r2, g2, b2, a2, + cyclic); + } + finally + { + unlock(); + } + } + + @Override + protected void setPaintPixels(long pointer, int[] pixels, int w, int h, + int stride, boolean repeat, int x, int y) + { + try + { + lock(); + super.setPaintPixels(pointer, pixels, w, h, stride, repeat, x, y); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSetMatrix(long pointer, double[] m) + { + try + { + lock(); + super.cairoSetMatrix(pointer, m); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoScale(long pointer, double x, double y) + { + try + { + lock(); + super.cairoScale(pointer, x, y); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSetOperator(long pointer, int cairoOperator) + { + try + { + lock(); + super.cairoSetOperator(pointer, cairoOperator); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSetRGBAColor(long pointer, double red, double green, + double blue, double alpha) + { + try + { + lock(); + super.cairoSetRGBAColor(pointer, red, green, blue, alpha); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSetFillRule(long pointer, int cairoFillRule) + { + try + { + lock(); + super.cairoSetFillRule(pointer, cairoFillRule); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSetLine(long pointer, double width, int cap, int join, + double miterLimit) + { + try + { + lock(); + super.cairoSetLine(pointer, width, cap, join, miterLimit); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSetDash(long pointer, double[] dashes, int ndash, + double offset) + { + try + { + lock(); + super.cairoSetDash(pointer, dashes, ndash, offset); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoRectangle(long pointer, double x, double y, + double width, double height) + { + try + { + lock(); + super.cairoRectangle(pointer, x, y, width, height); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoArc(long pointer, double x, double y, + double radius, double angle1, double angle2) + { + try + { + lock(); + super.cairoArc(pointer, x, y, radius, angle1, angle2); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSave(long pointer) + { + try + { + lock(); + super.cairoSave(pointer); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoRestore(long pointer) + { + try + { + lock(); + super.cairoRestore(pointer); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoNewPath(long pointer) + { + try + { + lock(); + super.cairoNewPath(pointer); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoClosePath(long pointer) + { + try + { + lock(); + super.cairoClosePath(pointer); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoMoveTo(long pointer, double x, double y) + { + try + { + lock(); + super.cairoMoveTo(pointer, x, y); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoLineTo(long pointer, double x, double y) + { + try + { + lock(); + super.cairoLineTo(pointer, x, y); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoCurveTo(long pointer, double x1, double y1, double x2, + double y2, double x3, double y3) + { + try + { + lock(); + super.cairoCurveTo(pointer, x1, y1, x2, y2, x3, y3); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoStroke(long pointer) + { + try + { + lock(); + super.cairoStroke(pointer); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoFill(long pointer, double alpha) + { + try + { + lock(); + super.cairoFill(pointer, alpha); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoClip(long pointer) + { + try + { + lock(); + super.cairoClip(pointer); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoResetClip(long pointer) + { + try + { + lock(); + super.cairoResetClip(pointer); + } + finally + { + unlock(); + } + } + + @Override + protected void cairoSetAntialias(long pointer, boolean aa) + { + try + { + lock(); + super.cairoSetAntialias(pointer, aa); + } + finally + { + unlock(); + } + } + + @Override + protected void drawCairoSurface(CairoSurface surface, AffineTransform tx, + double alpha, int interpolation) + { + try + { + lock(); + super.drawCairoSurface(surface, tx, alpha, interpolation); + } + finally + { + unlock(); + } + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphicsCopy.java b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphicsCopy.java new file mode 100644 index 000000000..a73012d9f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/ComponentGraphicsCopy.java @@ -0,0 +1,122 @@ +/* ComponentGraphicsCopy.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Color; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.image.RenderedImage; +import java.awt.image.ImageObserver; + +/** + * Implementation of Graphics2D for Components for servers which + * do not have xrender. + * + * A mirrored GtkImage of the component is stored in memory + * and copied back. Yay. + */ +public class ComponentGraphicsCopy extends CairoSurfaceGraphics +{ + private GtkComponentPeer component; + + /** + * GtkImage sharing its data buffer with this Cairo surface. + */ + private GtkImage gtkimage; + + private int width, height; + + native void getPixbuf( GtkComponentPeer component, GtkImage image ); + + native void copyPixbuf( GtkComponentPeer component, GtkImage image, + int x, int y, int w, int h ); + + public ComponentGraphicsCopy(int width, int height, + GtkComponentPeer component) + { + super( new CairoSurface( width, height ) ); + this.component = component; + this.width = width; + this.height = height; + gtkimage = surface.getGtkImage(); + getPixbuf( component, gtkimage ); + } + + /** + * Overloaded methods that do actual drawing need to enter the gdk threads + * and also do certain things before and after. + */ + public void draw(Shape s) + { + super.draw(s); + Rectangle r = s.getBounds(); + copyPixbuf(component, gtkimage, r.x, r.y, r.width, r.height); + } + + public void fill(Shape s) + { + super.fill(s); + Rectangle r = s.getBounds(); + copyPixbuf(component, gtkimage, r.x, r.y, r.width, r.height); + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + super.drawRenderedImage(image, xform); + copyPixbuf(component, gtkimage, 0, 0, width, height); + } + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + boolean rv = super.drawImage(img, xform, bgcolor, obs); + copyPixbuf(component, gtkimage, 0, 0, width, height); + return rv; + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + super.drawGlyphVector(gv, x, y); + Rectangle r = gv.getPixelBounds(getFontRenderContext(), x , y); + copyPixbuf(component, gtkimage, r.x, r.y, r.width, r.height); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java b/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java new file mode 100644 index 000000000..8fd734799 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java @@ -0,0 +1,630 @@ +/* FreetypeGlyphVector.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.gtk; + +import java.awt.Font; +import java.awt.Shape; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphJustificationInfo; +import java.awt.font.GlyphMetrics; +import java.awt.font.GlyphVector; +import java.awt.font.TextAttribute; +import java.awt.font.TransformAttribute; +import java.awt.geom.AffineTransform; +import java.awt.geom.GeneralPath; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.Arrays; + +public class FreetypeGlyphVector extends GlyphVector +{ + /** + * The associated font and its peer. + */ + private Font font; + private GdkFontPeer peer; // ATTN: Accessed from native code. + + private Rectangle2D logicalBounds; + + private float[] glyphPositions; + /** + * The string represented by this GlyphVector. + */ + private String s; + + /** + * The font render context + */ + private FontRenderContext frc; + + /** + * The total # of glyphs. + */ + private int nGlyphs; + + /** + * The glyph codes + */ + private int[] glyphCodes; + + /** + * The set of fonts used in this glyph vector. + */ + private long[] fontSet = null; + + /** + * Glyph transforms. Supports all transform operations. + * + * The identity transform should not be stored in this array; use a null + * instead (will result in performance improvements). + */ + private AffineTransform[] glyphTransforms; + + private GlyphMetrics[] metricsCache; + + private native void dispose(long[] fonts); + + /** + * Returns a pointer to the native PangoFcFont object. + * + * The object will be referenced with g_object_ref n times before being + * returned, and must be unreferenced a corresponding number of times. + * + * @param n Number of times to reference the object. + * @return Pointer to the native default font. + */ + private native long getNativeFontPointer(int n); + + /** + * Create a glyphvector from a given (Freetype) font and a String. + */ + public FreetypeGlyphVector(Font f, String s, FontRenderContext frc) + { + this(f, s.toCharArray(), 0, s.length(), frc, Font.LAYOUT_LEFT_TO_RIGHT); + } + + /** + * Create a glyphvector from a given (Freetype) font and a String. + */ + public FreetypeGlyphVector(Font f, char[] chars, int start, int len, + FontRenderContext frc, int flags) + { + this.s = new String(chars, start, len); + + this.font = f; + this.frc = frc; + if( !(font.getPeer() instanceof GdkFontPeer ) ) + throw new IllegalArgumentException("Not a valid font."); + peer = (GdkFontPeer)font.getPeer(); + + getGlyphs(); + if( flags == Font.LAYOUT_RIGHT_TO_LEFT ) + { + // reverse the glyph ordering. + int[] temp = new int[ nGlyphs ]; + for(int i = 0; i < nGlyphs; i++) + temp[i] = glyphCodes[nGlyphs - i - 1]; + glyphCodes = temp; + } + performDefaultLayout(); + } + + /** + * Create a glyphvector from a given set of glyph codes. + */ + public FreetypeGlyphVector(Font f, int[] codes, FontRenderContext frc) + { + this.font = f; + this.frc = frc; + if( !(font.getPeer() instanceof GdkFontPeer ) ) + throw new IllegalArgumentException("Not a valid font."); + peer = (GdkFontPeer)font.getPeer(); + + glyphCodes = new int[ codes.length ]; + System.arraycopy(codes, 0, glyphCodes, 0, codes.length); + nGlyphs = glyphCodes.length; + + if (fontSet == null) + { + fontSet = new long[nGlyphs]; + Arrays.fill(fontSet, getNativeFontPointer(nGlyphs)); + } + + performDefaultLayout(); + } + + /** + * Cloning constructor + */ + private FreetypeGlyphVector( FreetypeGlyphVector gv ) + { + font = gv.font; + peer = gv.peer; + frc = gv.frc; + s = gv.s; + nGlyphs = gv.nGlyphs; + logicalBounds = gv.logicalBounds.getBounds2D(); + + if( gv.metricsCache != null ) + { + metricsCache = new GlyphMetrics[ nGlyphs ]; + System.arraycopy(gv.metricsCache, 0, metricsCache, 0, nGlyphs); + } + + glyphCodes = new int[ nGlyphs ]; + fontSet = new long[nGlyphs]; + glyphPositions = new float[(nGlyphs + 1) * 2]; + glyphTransforms = new AffineTransform[ nGlyphs ]; + Arrays.fill(glyphTransforms, null); + + for(int i = 0; i < nGlyphs; i++ ) + { + if (gv.glyphTransforms[i] != null) + glyphTransforms[ i ] = new AffineTransform(gv.glyphTransforms[i]); + glyphCodes[i] = gv.glyphCodes[ i ]; + } + System.arraycopy(gv.glyphPositions, 0, glyphPositions, 0, + glyphPositions.length); + System.arraycopy(gv.glyphCodes, 0, glyphCodes, 0, nGlyphs); + System.arraycopy(gv.fontSet, 0, fontSet, 0, nGlyphs); + } + + public void finalize() + { + dispose(fontSet); + } + + /** + * Create the array of glyph codes. + */ + private void getGlyphs() + { + nGlyphs = s.codePointCount( 0, s.length() ); + glyphCodes = new int[ nGlyphs ]; + fontSet = new long[ nGlyphs ]; + int[] codePoints = new int[ nGlyphs ]; + int stringIndex = 0; + + for(int i = 0; i < nGlyphs; i++) + { + codePoints[i] = s.codePointAt( stringIndex ); + // UTF32 surrogate handling + if( codePoints[i] != (int)s.charAt( stringIndex ) ) + stringIndex ++; + stringIndex ++; + + if (Character.isISOControl(codePoints[i])) + { + // Replace with 'hair space'. Should better be 'zero-width space' + // but that doesn't seem to be supported by default font. + codePoints[i] = 8202; + } + } + + getGlyphs( codePoints, glyphCodes, fontSet ); + } + + /** + * Returns the glyph code within the font for a given character + */ + public native void getGlyphs(int[] codepoints, int[] glyphs, long[] fonts); + + /** + * Returns the kerning of a glyph pair + */ + private native void getKerning(int leftGlyph, int rightGlyph, long font, + float[] p); + + private native double[] getMetricsNative(int glyphCode, long font); + + private native GeneralPath getGlyphOutlineNative(int glyphIndex, long font); + + + public Object clone() + { + return new FreetypeGlyphVector( this ); + } + + /** + * Duh, compares two instances. + */ + public boolean equals(GlyphVector gv) + { + if( ! (gv instanceof FreetypeGlyphVector) ) + return false; + + return (((FreetypeGlyphVector)gv).font.equals(font) && + ((FreetypeGlyphVector)gv).frc.equals(frc) + && ((FreetypeGlyphVector)gv).s.equals(s)); + } + + /** + * Returns the associated Font + */ + public Font getFont() + { + return font; + } + + /** + * Returns the associated FontRenderContext + */ + public FontRenderContext getFontRenderContext() + { + return frc; + } + + /** + * Layout the glyphs. + */ + public void performDefaultLayout() + { + logicalBounds = null; // invalidate caches. + glyphTransforms = new AffineTransform[nGlyphs]; + Arrays.fill(glyphTransforms, null); + glyphPositions = new float[(nGlyphs + 1) * 2]; + + GlyphMetrics gm = null; + float x = 0; + float y = 0; + float[] p = {0.0f, 0.0f}; + for(int i = 0; i < nGlyphs; i++) + { + gm = getGlyphMetrics( i ); + glyphPositions[i*2] = x; + glyphPositions[i*2 + 1] = y; + + x += gm.getAdvanceX(); + y += gm.getAdvanceY(); + + // Get the kerning only if it's not the last glyph, and the two glyphs are + // using the same font + if (i != nGlyphs-1 && fontSet[i] == fontSet[i+1]) + { + getKerning(glyphCodes[i], glyphCodes[i + 1], fontSet[i], p); + x += p[0]; + y += p[1]; + } + } + glyphPositions[nGlyphs * 2] = x; + glyphPositions[nGlyphs * 2 + 1] = y; + + // Apply any transform that may be in the font's attributes + TransformAttribute ta; + ta = (TransformAttribute)font.getAttributes().get(TextAttribute.TRANSFORM); + if (ta != null) + { + AffineTransform tx = ta.getTransform(); + + // Transform glyph positions + tx.transform(glyphPositions, 0, glyphPositions, 0, + glyphPositions.length / 2); + + // Also store per-glyph scale/shear/rotate (but not translation) + double[] matrix = new double[4]; + tx.getMatrix(matrix); + AffineTransform deltaTx = new AffineTransform(matrix); + if (!deltaTx.isIdentity()) + Arrays.fill(glyphTransforms, deltaTx); + } + } + + /** + * Returns the code of the glyph at glyphIndex; + */ + public int getGlyphCode(int glyphIndex) + { + return glyphCodes[ glyphIndex ]; + } + + /** + * Returns multiple glyphcodes. + */ + public int[] getGlyphCodes(int beginGlyphIndex, int numEntries, + int[] codeReturn) + { + int[] rval; + + if( codeReturn == null || codeReturn.length < numEntries) + rval = new int[ numEntries ]; + else + rval = codeReturn; + + System.arraycopy(glyphCodes, beginGlyphIndex, rval, 0, numEntries); + + return rval; + } + + /** + * Returns pointers to the fonts used in this glyph vector. + * + * The array index matches that of the glyph vector itself. + */ + protected long[] getGlyphFonts(int beginGlyphIndex, int numEntries, + long[] codeReturn) + { + long[] rval; + + if( codeReturn == null || codeReturn.length < numEntries) + rval = new long[ numEntries ]; + else + rval = codeReturn; + + System.arraycopy(fontSet, beginGlyphIndex, rval, 0, numEntries); + + return rval; + } + + public Shape getGlyphLogicalBounds(int glyphIndex) + { + GlyphMetrics gm = getGlyphMetrics( glyphIndex ); + if( gm == null ) + return null; + Rectangle2D r = gm.getBounds2D(); + Point2D p = getGlyphPosition( glyphIndex ); + + double[] bounds = new double[] {p.getX() + r.getX() - gm.getLSB(), + p.getY() + r.getY(), + p.getX() + r.getX() - gm.getLSB() + gm.getAdvanceX(), + p.getY() + r.getY() + r.getHeight()}; + + if (glyphTransforms[glyphIndex] != null) + glyphTransforms[glyphIndex].transform(bounds, 0, bounds, 0, 2); + + return new Rectangle2D.Double(bounds[0], bounds[1], bounds[2] - bounds[0], + bounds[3] - bounds[1]); + } + + /* + * FIXME: Not all glyph types are supported. + * (The JDK doesn't really seem to do so either) + */ + public void setupGlyphMetrics() + { + metricsCache = new GlyphMetrics[ nGlyphs ]; + + for(int i = 0; i < nGlyphs; i++) + { + GlyphMetrics gm = (GlyphMetrics)peer.getGlyphMetrics(glyphCodes[i]); + if( gm == null ) + { + double[] val = getMetricsNative(glyphCodes[i], fontSet[i]); + if( val == null ) + gm = null; + else + { + gm = new GlyphMetrics(true, + (float)val[1], + (float)val[2], + new Rectangle2D.Double(val[3], val[4], + val[5], val[6] ), + GlyphMetrics.STANDARD ); + peer.putGlyphMetrics( glyphCodes[ i ], gm ); + } + } + metricsCache[ i ] = gm; + } + } + + /** + * Returns the metrics of a single glyph. + */ + public GlyphMetrics getGlyphMetrics(int glyphIndex) + { + if( metricsCache == null ) + setupGlyphMetrics(); + + return metricsCache[ glyphIndex ]; + } + + /** + * Returns the outline of a single glyph. + * + * Despite what the Sun API says, this method returns the glyph relative to + * the origin of the *entire string*, not each individual glyph. + */ + public Shape getGlyphOutline(int glyphIndex) + { + GeneralPath gp = getGlyphOutlineNative(glyphCodes[glyphIndex], + fontSet[glyphIndex]); + + AffineTransform tx = AffineTransform.getTranslateInstance(glyphPositions[glyphIndex*2], + glyphPositions[glyphIndex*2+1]); + if (glyphTransforms[glyphIndex] != null) + tx.concatenate( glyphTransforms[glyphIndex]); + + gp.transform(tx); + return gp; + } + + /** + * Returns the position of a single glyph. + */ + public Point2D getGlyphPosition(int glyphIndex) + { + return new Point2D.Float(glyphPositions[glyphIndex*2], + glyphPositions[glyphIndex*2 + 1]); + } + + /** + * Returns the positions of multiple glyphs. + */ + public float[] getGlyphPositions(int beginGlyphIndex, int numEntries, + float[] positionReturn) + { + if (positionReturn == null || positionReturn.length < (numEntries * 2)) + positionReturn = new float[numEntries*2]; + + System.arraycopy(glyphPositions, beginGlyphIndex*2, positionReturn, 0, + numEntries*2); + return positionReturn; + } + + /** + * Returns the transform of a glyph. + */ + public AffineTransform getGlyphTransform(int glyphIndex) + { + return glyphTransforms[glyphIndex]; + } + + /** + * Checks whether any transform has been set on any glyphs. + */ + protected boolean hasTransforms() + { + for (int i = 0; i < glyphTransforms.length; i++) + if (glyphTransforms[i] != null) + return true; + + return false; + } + + /** + * Returns the visual bounds of a glyph + * May be off by a pixel or two due to hinting/rasterization. + */ + public Shape getGlyphVisualBounds(int glyphIndex) + { + return getGlyphOutline( glyphIndex ).getBounds2D(); + } + + /** + * Return the logical bounds of the whole thing. + */ + public Rectangle2D getLogicalBounds() + { + if( nGlyphs == 0 ) + return new Rectangle2D.Double(0, 0, 0, 0); + if( logicalBounds != null ) + return logicalBounds; + + Rectangle2D rect = (Rectangle2D)getGlyphLogicalBounds( 0 ); + for( int i = 1; i < nGlyphs; i++ ) + { + Rectangle2D r2 = (Rectangle2D)getGlyphLogicalBounds( i ); + + rect = rect.createUnion( r2 ); + } + + logicalBounds = rect; + return rect; + } + + /** + * Returns the number of glyphs. + */ + public int getNumGlyphs() + { + return glyphCodes.length; + } + + /** + * Returns the outline of the entire GlyphVector. + */ + public Shape getOutline() + { + GeneralPath path = new GeneralPath(); + for( int i = 0; i < getNumGlyphs(); i++ ) + path.append(getGlyphOutline(i), false); + return path; + } + + /** + * TODO: + * FreeType does not currently have an API for the JSTF table. We should + * probably get the table ourselves from FT and pass it to some parser + * which the native font peers will need. + */ + public GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex) + { + return null; + } + + /** + * Returns the outline of the entire vector, drawn at (x,y). + */ + public Shape getOutline(float x, float y) + { + AffineTransform tx = AffineTransform.getTranslateInstance( x, y ); + GeneralPath gp = (GeneralPath)getOutline(); + gp.transform( tx ); + return gp; + } + + /** + * Returns the visual bounds of the entire GlyphVector. + * May be off by a pixel or two due to hinting/rasterization. + */ + public Rectangle2D getVisualBounds() + { + return getOutline().getBounds2D(); + } + + /** + * Sets the position of a glyph. + */ + public void setGlyphPosition(int glyphIndex, Point2D newPos) + { + glyphPositions[glyphIndex*2] = (float)(newPos.getX()); + glyphPositions[glyphIndex*2 + 1] = (float)(newPos.getY()); + logicalBounds = null; + } + + /** + * Sets the transform of a single glyph. + */ + public void setGlyphTransform(int glyphIndex, AffineTransform newTX) + { + // The identity transform should never be in the glyphTransforms array; + // using and checking for nulls can be much faster. + if (newTX != null && newTX.isIdentity()) + newTX = null; + + // If the old and new transforms are identical, bail + if (glyphTransforms[glyphIndex] == null && newTX == null) + return; + + if (newTX != null && newTX.equals(glyphTransforms[glyphIndex])) + return; + + // Invalidate bounds cache and set new transform + logicalBounds = null; + glyphTransforms[glyphIndex] = newTX; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java new file mode 100644 index 000000000..6b099063f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java @@ -0,0 +1,545 @@ +/* GdkFontPeer.java -- Implements FontPeer with GTK+ + Copyright (C) 1999, 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import gnu.classpath.Configuration; +import gnu.classpath.Pointer; + +import gnu.java.awt.ClasspathToolkit; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.font.opentype.NameDecoder; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Toolkit; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.GlyphMetrics; +import java.awt.font.LineMetrics; +import java.awt.font.TextLayout; +import java.awt.geom.Rectangle2D; +import java.text.CharacterIterator; +import java.util.Locale; +import java.util.Map; +import java.nio.ByteBuffer; +import java.util.HashMap; + +public class GdkFontPeer extends ClasspathFontPeer +{ + static final FontRenderContext DEFAULT_CTX = + new FontRenderContext(null, false, false); + + /** + * Caches TextLayout instances for use in charsWidth() and drawString(). + * The size of the cache has been chosen so that relativly large GUIs with + * text documents are still efficient. + */ + HashMap textLayoutCache = new GtkToolkit.LRUCache(500); + + private class GdkFontMetrics extends FontMetrics + { + + public GdkFontMetrics (Font font) + { + super(initFont(font)); + } + + public int stringWidth (String str) + { + TextLayout tl = textLayoutCache.get(str); + if (tl == null) + { + tl = new TextLayout(str, font, DEFAULT_CTX); + textLayoutCache.put(str, tl); + } + return (int) tl.getAdvance(); + } + + public int charWidth (char ch) + { + return stringWidth (new String (new char[] { ch })); + } + + public int charsWidth (char data[], int off, int len) + { + return stringWidth (new String (data, off, len)); + } + + public int getHeight() + { + return (int) height; + } + + public int getLeading () + { + return (int) (height - (ascent + descent)); + } + + public int getAscent () + { + return (int) ascent; + } + + public int getMaxAscent () + { + return (int) ascent; + } + + public int getDescent () + { + return (int) descent; + } + + public int getMaxDescent () + { + return (int) maxDescent; + } + + public int getMaxAdvance () + { + return (int) maxAdvance; + } + } + + static native void initStaticState(); + private final int native_state = GtkGenericPeer.getUniqueInteger (); + + /** + * Cache GlyphMetrics objects. + */ + private HashMap metricsCache; + + private static final int FONT_METRICS_ASCENT = 0; + private static final int FONT_METRICS_MAX_ASCENT = 1; + private static final int FONT_METRICS_DESCENT = 2; + private static final int FONT_METRICS_MAX_DESCENT = 3; + private static final int FONT_METRICS_MAX_ADVANCE = 4; + private static final int FONT_METRICS_HEIGHT = 5; + private static final int FONT_METRICS_UNDERLINE_OFFSET = 6; + private static final int FONT_METRICS_UNDERLINE_THICKNESS = 7; + + float ascent; + float descent; + float maxAscent; + float maxDescent; + float maxAdvance; + float height; + float underlineOffset; + float underlineThickness; + + GdkFontMetrics metrics; + + static + { + if (true) // GCJ LOCAL + { + System.loadLibrary("gtkpeer"); + } + + initStaticState (); + + } + + private ByteBuffer nameTable = null; + + /** + * The pointer to the native font data. + * + * This field is manipulated by native code. Don't change or remove + * without adjusting the native code. + */ + private Pointer nativeFont; + + private native void initState (); + private native void dispose (); + private native void setFont (String family, int style, int size); + + native synchronized void getFontMetrics(double [] metrics); + native synchronized void getTextMetrics(String str, double [] metrics); + + native void releasePeerGraphicsResource(); + + + protected void finalize () + { + releasePeerGraphicsResource(); + dispose (); + } + + /* + * Helpers for the 3-way overloading that this class seems to suffer + * from. Remove them if you feel like they're a performance bottleneck, + * for the time being I prefer my code not be written and debugged in + * triplicate. + */ + + private String buildString(CharacterIterator iter) + { + CPStringBuilder sb = new CPStringBuilder(); + for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) + sb.append(c); + return sb.toString(); + } + + private String buildString(CharacterIterator iter, int begin, int limit) + { + CPStringBuilder sb = new CPStringBuilder(); + int i = 0; + for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next(), i++) + { + if (begin <= i) + sb.append(c); + if (limit <= i) + break; + } + return sb.toString(); + } + + private String buildString(char[] chars, int begin, int limit) + { + return new String(chars, begin, limit - begin); + } + + /* Public API */ + + public GdkFontPeer (String name, int style) + { + // All fonts get a default size of 12 if size is not specified. + this(name, style, 12); + } + + public GdkFontPeer (String name, int style, int size) + { + super(name, style, size); + initState (); + setFont (this.familyName, this.style, (int)this.size); + metricsCache = new HashMap(); + setupMetrics(); + } + + public GdkFontPeer (String name, Map attributes) + { + super(name, attributes); + initState (); + setFont (this.familyName, this.style, (int)this.size); + metricsCache = new HashMap(); + setupMetrics(); + } + + + /** + * Makes sure to return a Font based on the given Font that has as + * peer a GdkFontPeer. Used in the initializer. + */ + static Font initFont(Font font) + { + if (font == null) + return new Font("Dialog", Font.PLAIN, 12); + else if (font.getPeer() instanceof GdkFontPeer) + return font; + else + { + ClasspathToolkit toolkit; + toolkit = (ClasspathToolkit) Toolkit.getDefaultToolkit(); + return toolkit.getFont(font.getName(), font.getAttributes()); + } + } + + private void setupMetrics() + { + double [] hires = new double[8]; + getFontMetrics(hires); + ascent = (float) hires[FONT_METRICS_ASCENT]; + maxAscent = (float) hires[FONT_METRICS_MAX_ASCENT]; + descent = (float) hires[FONT_METRICS_DESCENT]; + maxDescent = (float) hires[FONT_METRICS_MAX_DESCENT]; + maxAdvance = (float) hires[FONT_METRICS_MAX_ADVANCE]; + height = (float) hires[FONT_METRICS_HEIGHT]; + underlineOffset = (float) hires[FONT_METRICS_UNDERLINE_OFFSET]; + underlineThickness = (float) hires[FONT_METRICS_UNDERLINE_THICKNESS]; + } + + /** + * Unneeded, but implemented anyway. + */ + public String getSubFamilyName(Font font, Locale locale) + { + String name; + + if (locale == null) + locale = Locale.getDefault(); + + name = getName(NameDecoder.NAME_SUBFAMILY, locale); + if (name == null) + { + name = getName(NameDecoder.NAME_SUBFAMILY, Locale.ENGLISH); + if ("Regular".equals(name)) + name = null; + } + + return name; + } + + /** + * Returns the bytes belonging to a TrueType/OpenType table, + * Parameters n,a,m,e identify the 4-byte ASCII tag of the table. + * + * Returns null if the font is not TT, the table is nonexistant, + * or if some other unexpected error occured. + * + */ + private native byte[] getTrueTypeTable(byte n, byte a, byte m, byte e); + + /** + * Returns the PostScript name of the font, defaults to the familyName if + * a PS name could not be retrieved. + */ + public String getPostScriptName(Font font) + { + String name = getName(NameDecoder.NAME_POSTSCRIPT, + /* any language */ null); + if( name == null ) + return this.familyName; + + return name; + } + + /** + * Extracts a String from the font’s name table. + * + * @param name the numeric TrueType or OpenType name ID. + * + * @param locale the locale for which names shall be localized, or + * null if the locale does mot matter because the name + * is known to be language-independent (for example, because it is + * the PostScript name). + */ + private String getName(int name, Locale locale) + { + if (nameTable == null) + { + byte[] data = getTrueTypeTable((byte)'n', (byte) 'a', + (byte) 'm', (byte) 'e'); + if( data == null ) + return null; + + nameTable = ByteBuffer.wrap( data ); + } + + return NameDecoder.getName(nameTable, name, locale); + } + + public boolean canDisplay (Font font, int c) + { + // FIXME: inquire with pango + return true; + } + + public int canDisplayUpTo (Font font, CharacterIterator i, int start, int limit) + { + // FIXME: inquire with pango + return -1; + } + + public GlyphVector createGlyphVector (Font font, + FontRenderContext ctx, + CharacterIterator i) + { + return new FreetypeGlyphVector(font, buildString (i), ctx); + } + + public GlyphVector createGlyphVector (Font font, + FontRenderContext ctx, + int[] glyphCodes) + { + return new FreetypeGlyphVector(font, glyphCodes, ctx); + } + + public byte getBaselineFor (Font font, char c) + { + // FIXME: Actually check. + return Font.ROMAN_BASELINE; + } + + private class GdkFontLineMetrics extends LineMetrics + { + private int nchars; + public GdkFontLineMetrics (GdkFontPeer fp, int n) + { + nchars = n; + } + + public float getAscent() + { + return ascent; + } + + public int getBaselineIndex() + { + // FIXME + return Font.ROMAN_BASELINE; + } + + public float[] getBaselineOffsets() + { + return new float[3]; + } + + public float getDescent() + { + return descent; + } + + public float getHeight() + { + return height; + } + + public float getLeading() + { + return height - (ascent + descent); + } + + public int getNumChars() + { + return nchars; + } + + public float getStrikethroughOffset() + { + // FreeType doesn't seem to provide a value here. + return ascent / 2; + } + + public float getStrikethroughThickness() + { + // FreeType doesn't seem to provide a value here. + return 1.f; + } + + public float getUnderlineOffset() + { + return underlineOffset; + } + + public float getUnderlineThickness() + { + return underlineThickness; + } + + } + + public LineMetrics getLineMetrics (Font font, CharacterIterator ci, + int begin, int limit, FontRenderContext rc) + { + return new GdkFontLineMetrics (this, limit - begin); + } + + public Rectangle2D getMaxCharBounds (Font font, FontRenderContext rc) + { + throw new UnsupportedOperationException (); + } + + public int getMissingGlyphCode (Font font) + { + throw new UnsupportedOperationException (); + } + + public String getGlyphName (Font font, int glyphIndex) + { + throw new UnsupportedOperationException (); + } + + public int getNumGlyphs (Font font) + { + byte[] data = getTrueTypeTable((byte)'m', (byte) 'a', + (byte)'x', (byte) 'p'); + if( data == null ) + return -1; + + ByteBuffer buf = ByteBuffer.wrap( data ); + return buf.getShort(4); + } + + public boolean hasUniformLineMetrics (Font font) + { + return true; + } + + public GlyphVector layoutGlyphVector (Font font, FontRenderContext frc, + char[] chars, int start, int limit, + int flags) + { + return new FreetypeGlyphVector(font, chars, start, limit - start, + frc, flags); + } + + public LineMetrics getLineMetrics (Font font, String str, + FontRenderContext frc) + { + return new GdkFontLineMetrics (this, str.length ()); + } + + public FontMetrics getFontMetrics (Font font) + { + if (metrics == null) + metrics = new GdkFontMetrics(font); + return metrics; + } + + /** + * Returns a cached GlyphMetrics object for a given glyphcode, + * or null if it doesn't exist in the cache. + */ + GlyphMetrics getGlyphMetrics( int glyphCode ) + { + return metricsCache.get(new Integer(glyphCode)); + } + + /** + * Put a GlyphMetrics object in the cache. + */ + void putGlyphMetrics( int glyphCode, GlyphMetrics metrics ) + { + metricsCache.put( new Integer( glyphCode ), metrics ); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java new file mode 100644 index 000000000..40474ff3b --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsConfiguration.java @@ -0,0 +1,156 @@ +/* GdkGraphicsConfiguration.java -- describes characteristics of graphics + Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.gtk; + +import java.awt.BufferCapabilities; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.ImageCapabilities; +import java.awt.Rectangle; +import java.awt.Transparency; + +import java.awt.geom.AffineTransform; + +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.VolatileImage; + +public class GdkGraphicsConfiguration + extends GraphicsConfiguration +{ + GdkScreenGraphicsDevice gdkScreenGraphicsDevice; + + ColorModel opaqueColorModel; + + ColorModel bitmaskColorModel; + + ColorModel translucentColorModel; + + public GdkGraphicsConfiguration(GdkScreenGraphicsDevice dev) + { + gdkScreenGraphicsDevice = dev; + + opaqueColorModel = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, 0); + bitmaskColorModel = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, 0x1000000); + translucentColorModel = new DirectColorModel(32, 0xFF0000, 0xFF00, 0xFF, 0xFF000000); + } + + public GraphicsDevice getDevice() + { + return gdkScreenGraphicsDevice; + } + + public BufferedImage createCompatibleImage(int w, int h) + { + return new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + } + + public BufferedImage createCompatibleImage(int w, int h, + int transparency) + { + return createCompatibleImage(w, h); + } + + public VolatileImage createCompatibleVolatileImage(int w, int h) + { + return new GtkVolatileImage(w, h); + } + + public VolatileImage createCompatibleVolatileImage(int w, int h, + ImageCapabilities caps) + throws java.awt.AWTException + { + return new GtkVolatileImage(w, h, caps); + } + + public ColorModel getColorModel() + { + return opaqueColorModel; + } + + public ColorModel getColorModel(int transparency) + { + switch (transparency) + { + case Transparency.OPAQUE: + return opaqueColorModel; + case Transparency.BITMASK: + return bitmaskColorModel; + default: + case Transparency.TRANSLUCENT: + return translucentColorModel; + } + } + + public AffineTransform getDefaultTransform() + { + // FIXME: extract the GDK DPI information here. + return new AffineTransform(); + } + + public AffineTransform getNormalizingTransform() + { + // FIXME: extract the GDK DPI information here. + return new AffineTransform(); + } + + public Rectangle getBounds() + { + return gdkScreenGraphicsDevice.getBounds(); + } + + public BufferCapabilities getBufferCapabilities() + { + return new BufferCapabilities(getImageCapabilities(), + getImageCapabilities(), + BufferCapabilities.FlipContents.UNDEFINED); + } + + public ImageCapabilities getImageCapabilities() + { + return new ImageCapabilities(false); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, int transparency) + { + // FIXME: support the transparency argument + return new GtkVolatileImage(width, height); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java new file mode 100644 index 000000000..d931f4419 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkGraphicsEnvironment.java @@ -0,0 +1,172 @@ +/* GdkGraphicsEnvironment.java -- information about the graphics environment + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import gnu.classpath.Configuration; +import gnu.java.awt.ClasspathGraphicsEnvironment; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.WritableRaster; +import java.util.Locale; + +import gnu.classpath.Pointer; + +public class GdkGraphicsEnvironment extends ClasspathGraphicsEnvironment +{ + private final int native_state = GtkGenericPeer.getUniqueInteger (); + + private GdkScreenGraphicsDevice defaultDevice; + + private GdkScreenGraphicsDevice[] devices; + + /** + * The pointer to the native display resource. + * + * This field is manipulated by native code. Don't change or remove + * without adjusting the native code. + */ + private Pointer display; + + static + { + if (true) // GCJ LOCAL + { + System.loadLibrary("gtkpeer"); + } + + GtkToolkit.initializeGlobalIDs(); + initIDs(); + } + + private static native void initIDs(); + + public GdkGraphicsEnvironment () + { + nativeInitState(); + } + + native void nativeInitState(); + + public GraphicsDevice[] getScreenDevices () + { + if (devices == null) + { + devices = nativeGetScreenDevices(); + } + + return (GraphicsDevice[]) devices.clone(); + } + + private native GdkScreenGraphicsDevice[] nativeGetScreenDevices(); + + public GraphicsDevice getDefaultScreenDevice () + { + if (GraphicsEnvironment.isHeadless ()) + throw new HeadlessException (); + + synchronized (GdkGraphicsEnvironment.class) + { + if (defaultDevice == null) + { + defaultDevice = nativeGetDefaultScreenDevice(); + } + } + + return defaultDevice; + } + + private native GdkScreenGraphicsDevice nativeGetDefaultScreenDevice(); + + public Graphics2D createGraphics (BufferedImage image) + { + Raster raster = image.getRaster(); + if(raster instanceof CairoSurface) + return ((CairoSurface)raster).getGraphics(); + + return new BufferedImageGraphics( image ); + } + + private native int nativeGetNumFontFamilies(); + private native void nativeGetFontFamilies(String[] family_names); + + public Font[] getAllFonts () + { + throw new java.lang.UnsupportedOperationException (); + } + + public String[] getAvailableFontFamilyNames () + { + String[] family_names; + int array_size; + + array_size = nativeGetNumFontFamilies(); + family_names = new String[array_size]; + + nativeGetFontFamilies(family_names); + return family_names; + } + + public String[] getAvailableFontFamilyNames (Locale l) + { + throw new java.lang.UnsupportedOperationException (); + } + + /** + * Used by GtkMouseInfoPeer. + */ + native int[] getMouseCoordinates(); + native boolean isWindowUnderMouse(GtkWindowPeer windowPeer); + + public WritableRaster createRaster(ColorModel cm, SampleModel sm) + { + if (CairoSurface.isCompatibleSampleModel(sm) + && CairoSurface.isCompatibleColorModel(cm)) + return new CairoSurface(sm.getWidth(), sm.getHeight()); + else + return null; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java new file mode 100644 index 000000000..1b247c6eb --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java @@ -0,0 +1,785 @@ +/* GdkPixbufDecoder.java -- Image data decoding object + Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.util.ArrayList; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Locale; +import java.util.Vector; + +import javax.imageio.IIOImage; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageReader; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriteParam; +import javax.imageio.ImageWriter; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.spi.IIORegistry; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.spi.ImageWriterSpi; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageOutputStream; + +import gnu.classpath.Configuration; +import gnu.classpath.Pointer; + +public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder +{ + static + { + if (true) // GCJ LOCAL + { + System.loadLibrary("gtkpeer"); + } + + initStaticState (); + } + + /** + * Lock that should be held for all gdkpixbuf operations. We don't use + * the global gdk_threads_enter/leave functions since gdkpixbuf + * operations can be done in parallel to drawing and manipulating gtk + * widgets. + */ + static Object pixbufLock = new Object(); + + static native void initStaticState(); + private final int native_state = GtkGenericPeer.getUniqueInteger (); + + // initState() has been called, but pumpDone() has not yet been called. + private boolean needsClose = false; + + // the current set of ImageConsumers for this decoder + Vector curr; + + /** + * The pointer to the native pixbuf loader. + * + * This field is manipulated by native code. Don't change or remove + * without adjusting the native code. + */ + private Pointer nativeDecoder; + + // interface to GdkPixbuf + // These native functions should be called with the pixbufLock held. + native void initState (); + native void pumpBytes (byte[] bytes, int len) throws IOException; + native void pumpDone () throws IOException; + native void finish (boolean needsClose); + + /** + * Converts given image to bytes. + * Will call the GdkPixbufWriter for each chunk. + */ + static native void streamImage(int[] bytes, String format, + int width, int height, + boolean hasAlpha, GdkPixbufWriter writer); + + // gdk-pixbuf provids data in RGBA format + static final ColorModel cm = new DirectColorModel (32, 0xff000000, + 0x00ff0000, + 0x0000ff00, + 0x000000ff); + public GdkPixbufDecoder (DataInput datainput) + { + super (datainput); + } + + public GdkPixbufDecoder (InputStream in) + { + super (in); + } + + public GdkPixbufDecoder (String filename) + { + super (filename); + } + + public GdkPixbufDecoder (URL url) + { + super (url); + } + + public GdkPixbufDecoder (byte[] imagedata, int imageoffset, int imagelength) + { + super (imagedata, imageoffset, imagelength); + } + + // called back by native side: area_prepared_cb + void areaPrepared (int width, int height) + { + + if (curr == null) + return; + + for (int i = 0; i < curr.size (); i++) + { + ImageConsumer ic = (ImageConsumer) curr.elementAt (i); + ic.setDimensions (width, height); + ic.setColorModel (cm); + ic.setHints (ImageConsumer.RANDOMPIXELORDER); + } + } + + // called back by native side: area_updated_cb + void areaUpdated (int x, int y, int width, int height, + int pixels[], int scansize) + { + if (curr == null) + return; + + for (int i = 0; i < curr.size (); i++) + { + ImageConsumer ic = (ImageConsumer) curr.elementAt (i); + ic.setPixels (x, y, width, height, cm, pixels, 0, scansize); + } + } + + // called from an async image loader of one sort or another, this method + // repeatedly reads bytes from the input stream and passes them through a + // GdkPixbufLoader using the native method pumpBytes. pumpBytes in turn + // decodes the image data and calls back areaPrepared and areaUpdated on + // this object, feeding back decoded pixel blocks, which we pass to each + // of the ImageConsumers in the provided Vector. + + public void produce (Vector v, InputStream is) throws IOException + { + curr = v; + + byte bytes[] = new byte[4096]; + int len = 0; + synchronized(pixbufLock) + { + initState(); + } + needsClose = true; + + // Note: We don't want the pixbufLock while reading from the InputStream. + while ((len = is.read (bytes)) != -1) + { + synchronized(pixbufLock) + { + pumpBytes (bytes, len); + } + } + + synchronized(pixbufLock) + { + pumpDone(); + } + + needsClose = false; + + for (int i = 0; i < curr.size (); i++) + { + ImageConsumer ic = (ImageConsumer) curr.elementAt (i); + ic.imageComplete (ImageConsumer.STATICIMAGEDONE); + } + + curr = null; + } + + public void finalize() + { + synchronized(pixbufLock) + { + finish(needsClose); + } + } + + + public static class ImageFormatSpec + { + public String name; + public boolean writable = false; + public ArrayList mimeTypes = new ArrayList(); + public ArrayList extensions = new ArrayList(); + + public ImageFormatSpec(String name, boolean writable) + { + this.name = name; + this.writable = writable; + } + + public synchronized void addMimeType(String m) + { + mimeTypes.add(m); + } + + public synchronized void addExtension(String e) + { + extensions.add(e); + } + } + + static ArrayList imageFormatSpecs; + + public static ImageFormatSpec registerFormat(String name, boolean writable) + { + ImageFormatSpec ifs = new ImageFormatSpec(name, writable); + synchronized(GdkPixbufDecoder.class) + { + if (imageFormatSpecs == null) + imageFormatSpecs = new ArrayList(); + imageFormatSpecs.add(ifs); + } + return ifs; + } + + static String[] getFormatNames(boolean writable) + { + ArrayList names = new ArrayList(); + synchronized (imageFormatSpecs) + { + Iterator i = imageFormatSpecs.iterator(); + while (i.hasNext()) + { + ImageFormatSpec ifs = i.next(); + if (writable && !ifs.writable) + continue; + names.add(ifs.name); + + /* + * In order to make the filtering code work, we need to register + * this type under every "format name" likely to be used as a synonym. + * This generally means "all the extensions people might use". + */ + + Iterator j = ifs.extensions.iterator(); + while (j.hasNext()) + names.add(j.next()); + } + } + return names.toArray(new String[names.size()]); + } + + static String[] getFormatExtensions(boolean writable) + { + ArrayList extensions = new ArrayList(); + synchronized (imageFormatSpecs) + { + Iterator i = imageFormatSpecs.iterator(); + while (i.hasNext()) + { + ImageFormatSpec ifs = i.next(); + if (writable && !ifs.writable) + continue; + Iterator j = ifs.extensions.iterator(); + while (j.hasNext()) + extensions.add(j.next()); + } + } + return extensions.toArray(new String[extensions.size()]); + } + + static String[] getFormatMimeTypes(boolean writable) + { + ArrayList mimeTypes = new ArrayList(); + synchronized (imageFormatSpecs) + { + Iterator i = imageFormatSpecs.iterator(); + while (i.hasNext()) + { + ImageFormatSpec ifs = i.next(); + if (writable && !ifs.writable) + continue; + Iterator j = ifs.mimeTypes.iterator(); + while (j.hasNext()) + mimeTypes.add(j.next()); + } + } + return mimeTypes.toArray(new String[mimeTypes.size()]); + } + + + static String findFormatName(Object ext, boolean needWritable) + { + if (ext == null) + return null; + + if (!(ext instanceof String)) + throw new IllegalArgumentException("extension is not a string"); + + String str = (String) ext; + + Iterator i = imageFormatSpecs.iterator(); + while (i.hasNext()) + { + ImageFormatSpec ifs = i.next(); + + if (needWritable && !ifs.writable) + continue; + + if (ifs.name.equals(str)) + return str; + + Iterator j = ifs.extensions.iterator(); + while (j.hasNext()) + { + String extension = j.next(); + if (extension.equals(str)) + return ifs.name; + } + + j = ifs.mimeTypes.iterator(); + while (j.hasNext()) + { + String mimeType = j.next(); + if (mimeType.equals(str)) + return ifs.name; + } + } + throw new IllegalArgumentException("unknown extension '" + str + "'"); + } + + private static GdkPixbufReaderSpi readerSpi; + private static GdkPixbufWriterSpi writerSpi; + + public static synchronized GdkPixbufReaderSpi getReaderSpi() + { + if (readerSpi == null) + readerSpi = new GdkPixbufReaderSpi(); + return readerSpi; + } + + public static synchronized GdkPixbufWriterSpi getWriterSpi() + { + if (writerSpi == null) + writerSpi = new GdkPixbufWriterSpi(); + return writerSpi; + } + + public static void registerSpis(IIORegistry reg) + { + reg.registerServiceProvider(getReaderSpi(), ImageReaderSpi.class); + reg.registerServiceProvider(getWriterSpi(), ImageWriterSpi.class); + } + + public static class GdkPixbufWriterSpi extends ImageWriterSpi + { + public GdkPixbufWriterSpi() + { + super("GdkPixbuf", "2.x", + GdkPixbufDecoder.getFormatNames(true), + GdkPixbufDecoder.getFormatExtensions(true), + GdkPixbufDecoder.getFormatMimeTypes(true), + "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufWriter", + new Class[] { ImageOutputStream.class }, + new String[] { "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufReaderSpi" }, + false, null, null, null, null, + false, null, null, null, null); + } + + public boolean canEncodeImage(ImageTypeSpecifier ts) + { + return true; + } + + public ImageWriter createWriterInstance(Object ext) + { + return new GdkPixbufWriter(this, ext); + } + + public String getDescription(java.util.Locale loc) + { + return "GdkPixbuf Writer SPI"; + } + + } + + public static class GdkPixbufReaderSpi extends ImageReaderSpi + { + public GdkPixbufReaderSpi() + { + super("GdkPixbuf", "2.x", + GdkPixbufDecoder.getFormatNames(false), + GdkPixbufDecoder.getFormatExtensions(false), + GdkPixbufDecoder.getFormatMimeTypes(false), + "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufReader", + new Class[] { ImageInputStream.class }, + new String[] { "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufWriterSpi" }, + false, null, null, null, null, + false, null, null, null, null); + } + + public boolean canDecodeInput(Object obj) + { + return true; + } + + public ImageReader createReaderInstance(Object ext) + { + return new GdkPixbufReader(this, ext); + } + + public String getDescription(Locale loc) + { + return "GdkPixbuf Reader SPI"; + } + } + + private static class GdkPixbufWriter + extends ImageWriter implements Runnable + { + String ext; + public GdkPixbufWriter(GdkPixbufWriterSpi ownerSpi, Object ext) + { + super(ownerSpi); + this.ext = findFormatName(ext, true); + } + + public IIOMetadata convertImageMetadata (IIOMetadata inData, + ImageTypeSpecifier imageType, + ImageWriteParam param) + { + return null; + } + + public IIOMetadata convertStreamMetadata (IIOMetadata inData, + ImageWriteParam param) + { + return null; + } + + public IIOMetadata getDefaultImageMetadata (ImageTypeSpecifier imageType, + ImageWriteParam param) + { + return null; + } + + public IIOMetadata getDefaultStreamMetadata (ImageWriteParam param) + { + return null; + } + + public void write (IIOMetadata streamMetadata, IIOImage i, ImageWriteParam param) + throws IOException + { + RenderedImage image = i.getRenderedImage(); + Raster ras = image.getData(); + int width = ras.getWidth(); + int height = ras.getHeight(); + ColorModel model = image.getColorModel(); + int[] pixels = CairoGraphics2D.findSimpleIntegerArray (image.getColorModel(), ras); + + if (pixels == null) + { + BufferedImage img; + if(model != null && model.hasAlpha()) + img = CairoSurface.getBufferedImage(width, height); + img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + int[] pix = new int[4]; + for (int y = 0; y < height; ++y) + for (int x = 0; x < width; ++x) + img.setRGB(x, y, model.getRGB(ras.getPixel(x, y, pix))); + pixels = CairoGraphics2D.findSimpleIntegerArray (img.getColorModel(), + img.getRaster()); + model = img.getColorModel(); + } + + Thread workerThread = new Thread(this, "GdkPixbufWriter"); + workerThread.start(); + processImageStarted(1); + synchronized(pixbufLock) + { + streamImage(pixels, this.ext, width, height, model.hasAlpha(), + this); + } + synchronized(data) + { + data.add(DATADONE); + data.notifyAll(); + } + + while (workerThread.isAlive()) + { + try + { + workerThread.join(); + } + catch (InterruptedException ioe) + { + // Ignored. + } + } + + if (exception != null) + throw exception; + + processImageComplete(); + } + + /** + * Object marking end of data from native streamImage code. + */ + private static final Object DATADONE = new Object(); + + /** + * Holds the data gotten from the native streamImage code. + * A worker thread will pull data out. + * Needs to be synchronized for access. + * The special object DATADONE is added when all data has been delivered. + */ + private ArrayList data = new ArrayList(); + + /** + * Holds any IOException thrown by the run method that needs + * to be rethrown by the write method. + */ + private IOException exception; + + /** Callback for streamImage native code. **/ + private void write(byte[] bs) + { + synchronized(data) + { + data.add(bs); + data.notifyAll(); + } + } + + public void run() + { + boolean done = false; + while (!done) + { + synchronized(data) + { + while (data.isEmpty()) + { + try + { + data.wait(); + } + catch (InterruptedException ie) + { + /* ignore */ + } + } + + Object o = data.remove(0); + if (o == DATADONE) + done = true; + else + { + DataOutput out = (DataOutput) getOutput(); + try + { + out.write((byte[]) o); + } + catch (IOException ioe) + { + // We are only interested in the first exception. + if (exception == null) + exception = ioe; + } + } + } + } + } + } + + private static class GdkPixbufReader + extends ImageReader + implements ImageConsumer + { + // ImageConsumer parts + GdkPixbufDecoder dec; + BufferedImage bufferedImage; + ColorModel defaultModel; + int width; + int height; + String ext; + + public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext) + { + super(ownerSpi); + this.ext = findFormatName(ext, false); + } + + public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext, + GdkPixbufDecoder d) + { + this(ownerSpi, ext); + dec = d; + } + + public void setDimensions(int w, int h) + { + processImageStarted(1); + width = w; + height = h; + } + + public void setProperties(Hashtable props) {} + + public void setColorModel(ColorModel model) + { + defaultModel = model; + } + + public void setHints(int flags) {} + + public void setPixels(int x, int y, int w, int h, + ColorModel model, byte[] pixels, + int offset, int scansize) + { + } + + public void setPixels(int x, int y, int w, int h, + ColorModel model, int[] pixels, + int offset, int scansize) + { + if (model == null) + model = defaultModel; + + if (bufferedImage == null) + { + if(model != null && model.hasAlpha()) + bufferedImage = new BufferedImage (width, height, + BufferedImage.TYPE_INT_ARGB); + else + bufferedImage = new BufferedImage (width, height, + BufferedImage.TYPE_INT_RGB); + } + + int pixels2[]; + if (model != null) + { + pixels2 = new int[pixels.length]; + for (int yy = 0; yy < h; yy++) + for (int xx = 0; xx < w; xx++) + { + int i = yy * scansize + xx; + pixels2[i] = model.getRGB (pixels[i]); + } + } + else + pixels2 = pixels; + + bufferedImage.setRGB (x, y, w, h, pixels2, offset, scansize); + processImageProgress(y / (height == 0 ? 1 : height)); + } + + public void imageComplete(int status) + { + processImageComplete(); + } + + public BufferedImage getBufferedImage() + { + if (bufferedImage == null && dec != null) + dec.startProduction (this); + return bufferedImage; + } + + // ImageReader parts + + public int getNumImages(boolean allowSearch) + throws IOException + { + return 1; + } + + public IIOMetadata getImageMetadata(int i) + { + return null; + } + + public IIOMetadata getStreamMetadata() + throws IOException + { + return null; + } + + public Iterator getImageTypes(int imageIndex) + throws IOException + { + BufferedImage img = getBufferedImage(); + Vector vec = new Vector(); + vec.add(new ImageTypeSpecifier(img)); + return vec.iterator(); + } + + public int getHeight(int imageIndex) + throws IOException + { + return getBufferedImage().getHeight(); + } + + public int getWidth(int imageIndex) + throws IOException + { + return getBufferedImage().getWidth(); + } + + public void setInput(Object input, + boolean seekForwardOnly, + boolean ignoreMetadata) + { + super.setInput(input, seekForwardOnly, ignoreMetadata); + Object get = getInput(); + if (get instanceof InputStream) + dec = new GdkPixbufDecoder((InputStream) get); + else if (get instanceof DataInput) + dec = new GdkPixbufDecoder((DataInput) get); + else + throw new IllegalArgumentException("input object not supported: " + + get); + } + + public BufferedImage read(int imageIndex, ImageReadParam param) + throws IOException + { + return getBufferedImage (); + } + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkRobotPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkRobotPeer.java new file mode 100644 index 000000000..2609bad09 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkRobotPeer.java @@ -0,0 +1,99 @@ +/* GdkRobot.java -- an XTest implementation of RobotPeer + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.gtk; + +import java.awt.AWTException; +import java.awt.GraphicsDevice; +import java.awt.Rectangle; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.peer.RobotPeer; + +/** + * Implements the RobotPeer interface using the XTest extension. + * + * @author Thomas Fitzsimmons + */ +public class GdkRobotPeer implements RobotPeer +{ + // gdk-pixbuf provides data in RGBA format + static final ColorModel cm = new DirectColorModel (32, 0xff000000, + 0x00ff0000, + 0x0000ff00, + 0x000000ff); + + public GdkRobotPeer (GraphicsDevice screen) throws AWTException + { + // FIXME: make use of screen parameter when GraphicsDevice is + // implemented. + if (!initXTest ()) + throw new AWTException ("XTest extension not supported"); + } + + native boolean initXTest (); + + // RobotPeer methods + public native void mouseMove (int x, int y); + public native void mousePress (int buttons); + public native void mouseRelease (int buttons); + public native void mouseWheel (int wheelAmt); + public native void keyPress (int keycode); + public native void keyRelease (int keycode); + native int[] nativeGetRGBPixels (int x, int y, int width, int height); + + public int getRGBPixel (int x, int y) + { + return cm.getRGB (nativeGetRGBPixels (x, y, 1, 1)[0]); + } + + public int[] getRGBPixels (Rectangle r) + { + int[] gdk_pixels = nativeGetRGBPixels (r.x, r.y, r.width, r.height); + int[] pixels = new int[r.width * r.height]; + + for (int i = 0; i < r.width * r.height; i++) + pixels[i] = cm.getRGB (gdk_pixels[i]); + + return pixels; + } + + public void dispose() + { + // Nothing to do here yet. + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java b/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java new file mode 100644 index 000000000..1c849dfc0 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GdkScreenGraphicsDevice.java @@ -0,0 +1,362 @@ +/* GdkScreenGraphicsDevice.java -- information about a screen device + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.DisplayMode; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.Rectangle; +import java.awt.Window; +import java.util.ArrayList; + +import gnu.classpath.Configuration; +import gnu.classpath.Pointer; + +class GdkScreenGraphicsDevice extends GraphicsDevice +{ + private final int native_state = GtkGenericPeer.getUniqueInteger (); + + private Window fullscreenWindow; + + private boolean oldWindowDecorationState; + + private Rectangle oldWindowBounds; + + private Rectangle bounds; + + private GdkGraphicsConfiguration[] configurations; + + /** The GdkGraphicsEnvironment instance that created this + * GdkScreenGraphicsDevice. This is only needed for native + * methods which need to access the 'native_state' field storing a pointer + * to a GdkDisplay object. + */ + GdkGraphicsEnvironment env; + + /** An identifier that is created by Gdk + */ + String idString; + + /** The display modes supported by this GdkScreenGraphicsDevice. + * If the array is null nativeGetDisplayModes has + * to be called. + */ + X11DisplayMode[] displayModes; + + /** The non-changeable display mode of this GdkScreenGraphicsDevice + * . This field gets initialized by the {@link #init()} method. If it + * is still null afterwards, the XRandR extension is available + * and display mode changes are possible. If it is non-null XRandR is not + * available, no display mode changes are possible and no other native + * method must be called. + */ + DisplayMode fixedDisplayMode; + + /** + * The pointer to the native screen resource. + * + * This field is manipulated by native code. Don't change or remove + * without adjusting the native code. + */ + private Pointer screen; + + static + { + if (true) // GCJ LOCAL + { + System.loadLibrary("gtkpeer"); + } + + GtkToolkit.initializeGlobalIDs(); + initIDs(); + } + + static native void initIDs(); + + GdkScreenGraphicsDevice (GdkGraphicsEnvironment e) + { + super(); + env = e; + + configurations = new GdkGraphicsConfiguration[1]; + configurations[0] = new GdkGraphicsConfiguration(this); + } + + /** This method is called from the native side immediately after + * the constructor is run. + */ + void init() + { + fixedDisplayMode = nativeGetFixedDisplayMode(env); + } + + /** Depending on the availability of the XRandR extension the method returns + * the screens' non-changeable display mode or null, meaning that XRandR can + * handle display mode changes. + */ + native DisplayMode nativeGetFixedDisplayMode(GdkGraphicsEnvironment env); + + public int getType () + { + // Gdk manages only raster screens. + return GraphicsDevice.TYPE_RASTER_SCREEN; + } + + public String getIDstring () + { + if (idString == null) + idString = nativeGetIDString(); + + return idString; + } + + private native String nativeGetIDString(); + + public GraphicsConfiguration[] getConfigurations () + { + return (GraphicsConfiguration[]) configurations.clone(); + } + + public GraphicsConfiguration getDefaultConfiguration () + { + return configurations[0]; + } + + + /** + * Returns the current display mode of this device, or null if unknown. + * + * @return the current display mode + * @see #setDisplayMode(DisplayMode) + * @see #getDisplayModes() + * @since 1.4 + */ + public DisplayMode getDisplayMode() + { + if (fixedDisplayMode != null) + return fixedDisplayMode; + + synchronized (this) + { + if (displayModes == null) + displayModes = nativeGetDisplayModes(env); + } + + int index = nativeGetDisplayModeIndex(env); + int rate = nativeGetDisplayModeRate(env); + + return new DisplayMode(displayModes[index].width, + displayModes[index].height, + DisplayMode.BIT_DEPTH_MULTI, + rate); + } + + native int nativeGetDisplayModeIndex(GdkGraphicsEnvironment env); + + native int nativeGetDisplayModeRate(GdkGraphicsEnvironment env); + + public DisplayMode[] getDisplayModes() + { + if (fixedDisplayMode != null) + return new DisplayMode[] { fixedDisplayMode }; + + synchronized (this) + { + if (displayModes == null) + displayModes = nativeGetDisplayModes(env); + } + + ArrayList list = new ArrayList(); + for(int i=0;ifalse + * @since 1.4 + */ + public boolean isFullScreenSupported() + { + return true; + } + + public boolean isDisplayChangeSupported() + { + return fixedDisplayMode == null; + } + + public void setDisplayMode(DisplayMode dm) + { + if (fixedDisplayMode != null) + throw new UnsupportedOperationException("Cannnot change display mode."); + + if (dm == null) + throw new IllegalArgumentException("DisplayMode must not be null."); + + synchronized (this) + { + if (displayModes == null) + displayModes = nativeGetDisplayModes(env); + } + + for (int i=0; i groupMap + = new WeakHashMap(); + + public native void createCheckButton (); + public native void createRadioButton (long groupPointer); + + public native void addToGroup (long groupPointer); + public native void removeFromGroup (); + public native void switchToGroup (long groupPointer); + + public native void connectSignals (); + + /** + * Overridden to set Font of label inside button. + */ + protected native void gtkWidgetModifyFont(String name, int style, int size); + native void gtkButtonSetLabel (String label); + native void gtkToggleButtonSetActive (boolean is_active); + + public GtkCheckboxPeer (Checkbox c) + { + super (c); + } + + public void create () + { + Checkbox checkbox = (Checkbox) awtComponent; + current_group = checkbox.getCheckboxGroup (); + if (current_group == null) + { + // Initially we're not part of a group so we're backed by a + // GtkCheckButton. + createCheckButton(); + } + else + { + // Initially we're part of a group. + + // See if this group is already stored in our map. + Long groupPointer = null; + synchronized (groupMap) + { + groupPointer = groupMap.get(current_group); + } + + if (groupPointer == null) + { + // We don't know about this group. Create a new native + // group pointer for this group and store it in our map. + createRadioButton(0); + } + else + { + // We already know about this group. Pass the + // corresponding native group pointer value to the native + // create method. + createRadioButton(groupPointer.longValue()); + } + } + currentState = checkbox.getState(); + gtkToggleButtonSetActive(currentState); + + String label = checkbox.getLabel(); + if (label != null) + gtkButtonSetLabel(label); + } + + /** + * Sets native GtkCheckButton is state is different from current + * state. Will set currentState to state to prevent posting an + * event since events should only be posted for user initiated + * clicks on the GtkCheckButton. + */ + public synchronized void setState (boolean state) + { + if (currentState != state) + { + currentState = state; + gtkToggleButtonSetActive(state); + } + } + + public void setLabel (String label) + { + gtkButtonSetLabel (label); + } + + public void setCheckboxGroup (CheckboxGroup group) + { + if (current_group == null && group != null) + { + // This peer's owner is currently not in a group, and now + // we're adding it to a group. This means that the backing + // GtkWidget will change from a GtkCheckButton to a + // GtkRadioButton. + + current_group = group; + + // See if the new group is already stored in our map. + Long groupPointer = null; + synchronized (groupMap) + { + groupPointer = groupMap.get(current_group); + } + + if (groupPointer == null) + { + // We don't know about this group. Create a new native + // group pointer for this group and store it in our map. + addToGroup(0); + } + else + { + // We already know about this group. Pass the + // corresponding native group pointer value to the native + // create method. + addToGroup(groupPointer.longValue()); + } + } + else if (current_group != null && group == null) + { + // This peer's owner is currently in a group, and now we're + // removing it from a group. This means that the backing + // GtkWidget will change from a GtkRadioButton to a + // GtkCheckButton. + removeFromGroup(); + current_group = null; + } + else if (current_group == null && group == null) + { + // This peer's owner is currently not in a group, and we're + // not adding it to a group, so simply return. + return; + } + else if (current_group != group) + { + // This peer's owner is currently in a group, and now we're + // putting it in another group. This means that we must + // remove the backing GtkRadioButton from one group and add it + // to the other group. + + current_group = group; + + // See if the new group is already stored in our map. + Long groupPointer = null; + synchronized (groupMap) + { + groupPointer = groupMap.get(current_group); + } + + if (groupPointer == null) + { + // We don't know about this group. Create a new native + // group pointer for this group and store it in our map. + switchToGroup(0); + } + else + { + // We already know about this group. Pass the + // corresponding native group pointer value to the native + // create method. + switchToGroup(groupPointer.longValue()); + } + } + } + + // Override the superclass postItemEvent so that the peer doesn't + // need information that we have. + // called back by native side: item_toggled_cb + public synchronized void postItemEvent(Object item, boolean state) + { + // Only fire event is state actually changed. + if (currentState != state) + { + currentState = state; + super.postItemEvent(awtComponent, + state ? ItemEvent.SELECTED : ItemEvent.DESELECTED); + } + } + + public void addToGroupMap(long groupPointer) + { + synchronized (groupMap) + { + groupMap.put(current_group, new Long (groupPointer)); + } + } + + public void dispose () + { + groupMap.clear(); + current_group = null; + currentState = false; + super.dispose (); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java new file mode 100644 index 000000000..59cacf0b6 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkChoicePeer.java @@ -0,0 +1,142 @@ +/* GtkChoicePeer.java -- Implements ChoicePeer with GTK + Copyright (C) 1998, 1999, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Choice; +import java.awt.AWTEvent; +import java.awt.event.ItemEvent; +import java.awt.peer.ChoicePeer; + +public class GtkChoicePeer extends GtkComponentPeer + implements ChoicePeer +{ + private int selected; + + public GtkChoicePeer (Choice c) + { + super (c); + + int count = c.getItemCount (); + if (count > 0) + { + for (int i = 0; i < count; i++) + add(c.getItem(i), i); + + selected = c.getSelectedIndex(); + if (selected >= 0) + select( selected ); + } + else + selected = -1; + } + + native void create (); + + native int nativeGetSelected (); + + native void connectSignals (); + + native void selectNative (int position); + + native void selectNativeUnlocked (int position); + + public native void add (String item, int index); + + native void nativeRemove(int index); + + native void nativeRemoveAll(); + + public void select (int position) + { + if (Thread.currentThread() == GtkMainThread.mainThread) + selectNativeUnlocked (position); + else + selectNative (position); + } + + public void remove( int index ) + { + // Ensure the triggering of an event when removing item zero if zero is the + // selected item, even though the selected index doesn't change. + if( index == 0 && selected == 0 ) + selected = -1; + nativeRemove( index ); + } + + public void removeAll() + { + selected = -1; // we do not want to trigger a select event here. + nativeRemoveAll(); + } + + public void addItem (String item, int position) + { + add (item, position); + } + + /** + * Callback from the native side on an item-select event, + * which posts an event. The event is only posted if it represents an actual + * change. Selected is set to the peer's state initially, so that the + * first call to select(int) from the constructor will not trigger an event. + * (it should not) + */ + protected void postChoiceItemEvent ( int index ) + { + if( selected != index ) + { + selected = index; + postItemEvent (((Choice) awtComponent).getItem( selected ), + ItemEvent.SELECTED); + } + } + + /** + * Catches the event and calls Choice.select() if the component state + * needs updating. + */ + public void handleEvent (AWTEvent event) + { + super.handleEvent (event); + if (event instanceof ItemEvent) + if (((ItemEvent)event).getItemSelectable() == awtComponent + && ((ItemEvent)event).getStateChange() == ItemEvent.SELECTED) + ((Choice)awtComponent).select( selected ); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java new file mode 100644 index 000000000..4250cabaa --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboard.java @@ -0,0 +1,436 @@ +/* GtkClipboard.java + Copyright (C) 1999, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.Image; + +import java.awt.datatransfer.Clipboard; +import java.awt.datatransfer.ClipboardOwner; +import java.awt.datatransfer.DataFlavor; +import java.awt.datatransfer.StringSelection; +import java.awt.datatransfer.Transferable; +import java.awt.datatransfer.UnsupportedFlavorException; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.io.Reader; +import java.io.Serializable; +import java.io.UnsupportedEncodingException; + +import java.util.List; +import java.util.Iterator; + +public class GtkClipboard extends Clipboard +{ + /** + * The one and only gtk+ clipboard instance for the CLIPBOARD selection. + */ + final static GtkClipboard clipboard = new GtkClipboard("System Clipboard"); + + /** + * The one and only gtk+ clipboard instance for the PRIMARY selection. + */ + final static GtkClipboard selection = new GtkClipboard("System Selection"); + + // Given to the native side so it can signal special targets that + // can be converted to one of the special predefined DataFlavors. + static final String stringMimeType + = DataFlavor.stringFlavor.getMimeType(); + static final String imageMimeType + = DataFlavor.imageFlavor.getMimeType(); + static final String filesMimeType + = DataFlavor.javaFileListFlavor.getMimeType(); + + // Indicates whether the results of the clipboard selection can be + // cached by GtkSelection. True if + // gdk_display_supports_selection_notification. + static final boolean canCache = initNativeState(clipboard, selection, + stringMimeType, + imageMimeType, + filesMimeType); + + /** + * Creates the clipboard and sets the initial contents to the + * current gtk+ selection. + */ + private GtkClipboard(String name) + { + super(name); + setContents(new GtkSelection(this), null); + } + + /** + * Returns the one and only GtkClipboard instance for the CLIPBOARD + * selection. + */ + static GtkClipboard getClipboardInstance() + { + return clipboard; + } + + /** + * Returns the one and only GtkClipboard instance for the PRIMARY + * selection. + */ + static GtkClipboard getSelectionInstance() + { + return selection; + } + + /** + * Sets the GtkSelection facade as new contents of the clipboard. + * Called from gtk+ when another application grabs the clipboard and + * we loose ownership. + * + * @param cleared If true this is a clear event (someone takes the + * clipboard from us) otherwise it is an owner changed event. + */ + private synchronized void setSystemContents(boolean cleared) + { + // We need to notify clipboard owner listeners when we were the + // owner (the selection was explictly set) and someone takes the + // clipboard away from us and asks us the clear any held storage, + // or if we weren't the owner of the clipboard to begin with, but + // the clipboard contents changed. We could refine this and check + // whether the actual available formats did in fact change, but we + // assume listeners will check for that anyway (and if possible we + // ask to cache the available formats so even if multiple + // listeners check after a notification the overhead should be + // minimal). + boolean owner = ! (contents instanceof GtkSelection); + boolean needNotification = (cleared && owner) || (! cleared && ! owner); + if (needNotification) + GtkClipboardNotifier.announce(this); + } + + /** + * Sets the new contents and advertises the available flavors to the + * gtk+ clipboard. + */ + public synchronized void setContents(Transferable contents, + ClipboardOwner owner) + { + super.setContents(contents, owner); + + if (contents == null) + { + advertiseContent(null, false, false, false); + return; + } + + // We don't need to do anything for a GtkSelection facade. + if (contents instanceof GtkSelection) + return; + + boolean text = false; + boolean images = false; + boolean files = false; + + if (contents instanceof StringSelection + || contents.isDataFlavorSupported(DataFlavor.stringFlavor) + || contents.isDataFlavorSupported(DataFlavor.plainTextFlavor) + || contents.isDataFlavorSupported(DataFlavor.getTextPlainUnicodeFlavor())) + text = true; + + DataFlavor[] flavors = contents.getTransferDataFlavors(); + String[] mimeTargets = new String[flavors.length]; + for (int i = 0; i < flavors.length; i++) + { + DataFlavor flavor = flavors[i]; + String mimeType = flavor.getMimeType(); + mimeTargets[i] = mimeType; + + if (! text) + if ("text".equals(flavor.getPrimaryType()) + || flavor.isRepresentationClassReader()) + text = true; + + if (! images && flavors[i].equals(DataFlavor.imageFlavor)) + { + try + { + Object o = contents.getTransferData(DataFlavor.imageFlavor); + if (o instanceof Image) + images = true; + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } + } + + if (flavors[i].equals(DataFlavor.javaFileListFlavor)) + files = true; + } + + advertiseContent(mimeTargets, text, images, files); + } + + /** + * Advertises new contents to the gtk+ clipboard given a string + * array of (mime-type) targets. When the boolean flags text, images + * and/or files are set then gtk+ is asked to also advertise the + * availability of any text, image or uri/file content types it + * supports. If targets is null (and all flags false) then the + * selection has explicitly been erased. + */ + private native void advertiseContent(String[] targets, + boolean text, + boolean images, + boolean files); + + /** + * Called by the gtk+ clipboard when an application has requested + * text. Return a string representing the current clipboard + * contents or null when no text can be provided. + */ + private String provideText() + { + Transferable contents = this.contents; + if (contents == null || contents instanceof GtkSelection) + return null; + + // Handle StringSelection special since that is just pure text. + if (contents instanceof StringSelection) + { + try + { + return (String) contents.getTransferData(DataFlavor.stringFlavor); + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } + } + + // Try to get a plain text reader for the current contents and + // turn the result into a string. + try + { + DataFlavor plainText = DataFlavor.getTextPlainUnicodeFlavor(); + Reader r = plainText.getReaderForText(contents); + if (r != null) + { + CPStringBuilder sb = new CPStringBuilder(); + char[] cs = new char[1024]; + int l = r.read(cs); + while (l != -1) + { + sb.append(cs, 0, l); + l = r.read(cs); + } + return sb.toString(); + } + } + catch (IllegalArgumentException iae) + { + } + catch (UnsupportedEncodingException iee) + { + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + + return null; + } + + /** + * Called by the gtk+ clipboard when an application has requested an + * image. Returns a GtkImage representing the current clipboard + * contents or null when no image can be provided. + */ + private GtkImage provideImage() + { + Transferable contents = this.contents; + if (contents == null || contents instanceof GtkSelection) + return null; + + try + { + Object o = contents.getTransferData(DataFlavor.imageFlavor); + if( o instanceof GtkImage ) + return (GtkImage) o; + else + return new GtkImage(((Image)o).getSource()); + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } + + return null; + } + + /** + * Called by the gtk+ clipboard when an application has requested a + * uri-list. Return a string array containing the URIs representing + * the current clipboard contents or null when no URIs can be + * provided. + */ + private String[] provideURIs() + { + Transferable contents = this.contents; + if (contents == null || contents instanceof GtkSelection) + return null; + + try + { + List list = (List) contents.getTransferData(DataFlavor.javaFileListFlavor); + String[] uris = new String[list.size()]; + int u = 0; + Iterator it = list.iterator(); + while (it.hasNext()) + uris[u++] = ((File) it.next()).toURI().toString(); + return uris; + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } + + return null; + } + + /** + * Called by gtk+ clipboard when an application requests the given + * target mime-type. Returns a byte array containing the requested + * data, or null when the contents cannot be provided in the + * requested target mime-type. Only called after any explicit text, + * image or file/uri requests have been handled earlier and failed. + */ + private byte[] provideContent(String target) + { + // Sanity check. The callback could be triggered just after we + // changed the clipboard. + Transferable contents = this.contents; + if (contents == null || contents instanceof GtkSelection) + return null; + + // XXX - We are being called from a gtk+ callback. Which means we + // should return as soon as possible and not call arbitrary code + // that could deadlock or go bonkers. But we don't really know + // what DataTransfer contents object we are dealing with. Same for + // the other provideXXX() methods. + try + { + DataFlavor flavor = new DataFlavor(target); + Object o = contents.getTransferData(flavor); + + if (o instanceof byte[]) + return (byte[]) o; + + if (o instanceof InputStream) + { + InputStream is = (InputStream) o; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + byte[] bs = new byte[1024]; + int l = is.read(bs); + while (l != -1) + { + baos.write(bs, 0, l); + l = is.read(bs); + } + return baos.toByteArray(); + } + + if (o instanceof Serializable) + { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream oos = new ObjectOutputStream(baos); + oos.writeObject(o); + oos.close(); + return baos.toByteArray(); + } + } + catch (ClassNotFoundException cnfe) + { + } + catch (UnsupportedFlavorException ufe) + { + } + catch (IOException ioe) + { + } + catch (ClassCastException cce) + { + } + + return null; + } + + /** + * Initializes the gtk+ clipboards and caches any native side + * structures needed. Returns whether or not the contents of the + * Clipboard can be cached (gdk_display_supports_selection_notification). + */ + private static native boolean initNativeState(GtkClipboard clipboard, + GtkClipboard selection, + String stringTarget, + String imageTarget, + String filesTarget); +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java new file mode 100644 index 000000000..8e5934557 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkClipboardNotifier.java @@ -0,0 +1,129 @@ +/* GtkClipboardNotifier.java -- Helper for announcing GtkSelection changes. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + + +class GtkClipboardNotifier extends Thread +{ + /** Whether to announce a new GtkSelection has been set for CLIPBOARD. */ + static private boolean announceClipboardChange; + + /** Whether to announce a new GtkSelection has been set for PRIMARY. */ + static private boolean announcePrimaryChange; + + /** + * The one and only instance. All operations are synchronized on + * this. + */ + private static GtkClipboardNotifier notifier = new GtkClipboardNotifier(); + + /** + * Creates a deamon thread that monitors this for change + * announcements. + */ + private GtkClipboardNotifier() + { + super("GtkClipBoardNotifier"); + setDaemon(true); + start(); + } + + /** + * Notifies that a new GtkSelection has to be announced. + * + * @param clipboard either the GtkClipboard.clipboard or the + * GtkClipboard.selection. + */ + static void announce(GtkClipboard clipboard) + { + synchronized (notifier) + { + if (clipboard == GtkClipboard.clipboard) + announceClipboardChange = true; + else + announcePrimaryChange = true; + notifier.notifyAll(); + } + } + + public void run() + { + GtkClipboard clipboard; + while (true) + { + synchronized (this) + { + while (! announceClipboardChange && ! announcePrimaryChange) + { + try + { + this.wait(); + } + catch (InterruptedException ie) + { + // ignore + } + } + + if (announceClipboardChange) + { + clipboard = GtkClipboard.clipboard; + announceClipboardChange = false; + } + else + { + clipboard = GtkClipboard.selection; + announcePrimaryChange = false; + } + } + + // Do the actual announcement without the lock held. We will + // notice a new change after this notification has finished. + try + { + clipboard.setContents(new GtkSelection(clipboard), null); + } + catch (Throwable t) + { + // should never happen, but might if we have some faulty listener. + t.printStackTrace(); + } + } + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java new file mode 100644 index 000000000..6e5069bc1 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkComponentPeer.java @@ -0,0 +1,920 @@ +/* GtkComponentPeer.java -- Implements ComponentPeer with GTK + Copyright (C) 1998, 1999, 2002, 2004, 2005, 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.BufferCapabilities; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Insets; +import java.awt.ItemSelectable; +import java.awt.KeyboardFocusManager; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.FocusEvent; +import java.awt.event.ItemEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.event.PaintEvent; +import java.awt.event.TextEvent; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.VolatileImage; +import java.awt.peer.ComponentPeer; +import java.awt.peer.ContainerPeer; +import java.awt.peer.LightweightPeer; +import java.util.Timer; +import java.util.TimerTask; + +public class GtkComponentPeer extends GtkGenericPeer + implements ComponentPeer +{ + VolatileImage backBuffer; + BufferCapabilities caps; + + Component awtComponent; + + Insets insets; + + /** + * The current repaint area. Use should be guarded by synchronizing on this. + */ + private Rectangle currentPaintArea; + + /* this isEnabled differs from Component.isEnabled, in that it + knows if a parent is disabled. In that case Component.isEnabled + may return true, but our isEnabled will always return false */ + native boolean isEnabled (); + static native boolean modalHasGrab(); + + native int[] gtkWidgetGetForeground (); + native int[] gtkWidgetGetBackground (); + native void gtkWidgetGetDimensions (int[] dim); + native void gtkWidgetGetPreferredDimensions (int[] dim); + native void gtkWindowGetLocationOnScreen (int[] point); + native void gtkWindowGetLocationOnScreenUnlocked (int[] point); + native void gtkWidgetGetLocationOnScreen (int[] point); + native void gtkWidgetGetLocationOnScreenUnlocked (int[] point); + native void gtkWidgetSetCursor (int type, GtkImage image, int x, int y); + native void gtkWidgetSetCursorUnlocked (int type, GtkImage image, + int x, int y); + native void gtkWidgetSetBackground (int red, int green, int blue); + native void gtkWidgetSetForeground (int red, int green, int blue); + native void gtkWidgetSetSensitive (boolean sensitive); + native void gtkWidgetSetParent (ComponentPeer parent); + native void gtkWidgetRequestFocus (); + native void gtkWidgetDispatchKeyEvent (int id, long when, int mods, + int keyCode, int keyLocation); + native boolean gtkWidgetHasFocus(); + native boolean gtkWidgetCanFocus(); + + native void realize(); + native void setNativeEventMask (); + + void create () + { + throw new RuntimeException (); + } + + native void connectSignals (); + + protected GtkComponentPeer (Component awtComponent) + { + super (awtComponent); + this.awtComponent = awtComponent; + insets = new Insets (0, 0, 0, 0); + + create (); + + connectSignals (); + + if (awtComponent.getForeground () != null) + setForeground (awtComponent.getForeground ()); + if (awtComponent.getBackground () != null) + setBackground (awtComponent.getBackground ()); + if (awtComponent.getFont() != null) + setFont(awtComponent.getFont()); + + Component parent = awtComponent.getParent (); + + setParentAndBounds (); + + setNativeEventMask (); + + // This peer is guaranteed to have an X window upon construction. + // That is, native methods such as those in GdkGraphics can rely + // on this component's widget->window field being non-null. + realize (); + + if (awtComponent.isCursorSet()) + setCursor (); + } + + void setParentAndBounds () + { + setParent (); + + setComponentBounds (); + + setVisibleAndEnabled (); + } + + void setParent () + { + ComponentPeer p; + Component component = awtComponent; + do + { + component = component.getParent (); + p = component.getPeer (); + } + while (p instanceof java.awt.peer.LightweightPeer); + + if (p != null) + gtkWidgetSetParent (p); + } + + /* + * Set the bounds of this peer's AWT Component based on dimensions + * returned by the native windowing system. Most Components impose + * their dimensions on the peers which is what the default + * implementation does. However some peers, like GtkFileDialogPeer, + * need to pass their size back to the AWT Component. + */ + void setComponentBounds () + { + Rectangle bounds = awtComponent.getBounds (); + setBounds (bounds.x, bounds.y, bounds.width, bounds.height); + } + + void setVisibleAndEnabled () + { + setVisible (awtComponent.isVisible ()); + setEnabled (awtComponent.isEnabled ()); + } + + public int checkImage (Image image, int width, int height, + ImageObserver observer) + { + return getToolkit().checkImage(image, width, height, observer); + } + + public Image createImage (ImageProducer producer) + { + return new GtkImage (producer); + } + + public Image createImage (int width, int height) + { + return CairoSurface.getBufferedImage(width, height); + } + + public void disable () + { + setEnabled (false); + } + + public void enable () + { + setEnabled (true); + } + + public ColorModel getColorModel () + { + return ColorModel.getRGBdefault (); + } + + public FontMetrics getFontMetrics (Font font) + { + return getToolkit().getFontMetrics(font); + } + + // getGraphics may be overridden by derived classes but it should + // never return null. + public Graphics getGraphics () + { + return ComponentGraphics.getComponentGraphics(this); + } + + public Point getLocationOnScreen () + { + int point[] = new int[2]; + if (Thread.currentThread() == GtkMainThread.mainThread) + gtkWidgetGetLocationOnScreenUnlocked (point); + else + gtkWidgetGetLocationOnScreen (point); + return new Point (point[0], point[1]); + } + + public Dimension getMinimumSize () + { + return minimumSize (); + } + + public Dimension getPreferredSize () + { + return preferredSize (); + } + + public Toolkit getToolkit () + { + return Toolkit.getDefaultToolkit(); + } + + public void handleEvent (AWTEvent event) + { + int id = event.getID(); + KeyEvent ke = null; + + switch (id) + { + case PaintEvent.PAINT: + paintComponent((PaintEvent) event); + break; + case PaintEvent.UPDATE: + updateComponent((PaintEvent) event); + break; + case KeyEvent.KEY_PRESSED: + ke = (KeyEvent) event; + gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiersEx (), + ke.getKeyCode (), ke.getKeyLocation ()); + break; + case KeyEvent.KEY_RELEASED: + ke = (KeyEvent) event; + gtkWidgetDispatchKeyEvent (ke.getID (), ke.getWhen (), ke.getModifiersEx (), + ke.getKeyCode (), ke.getKeyLocation ()); + break; + } + } + + // This method and its overrides are the only methods in the peers + // that should call awtComponent.paint. + protected void paintComponent (PaintEvent event) + { + // Do not call Component.paint if the component is not showing or + // if its bounds form a degenerate rectangle. + if (!awtComponent.isShowing() + || (awtComponent.getWidth() < 1 || awtComponent.getHeight() < 1)) + return; + + // Creating and disposing a GdkGraphics every time paint is called + // seems expensive. However, the graphics state does not carry + // over between calls to paint, and resetting the graphics object + // may even be more costly than simply creating a new one. + + // Make sure that the paintArea includes the area from the event + // in the case when an application sends PaintEvents directly. + coalescePaintEvent(event); + Rectangle paintArea; + synchronized (this) + { + paintArea = currentPaintArea; + currentPaintArea = null; + } + + if (paintArea != null) + { + Graphics g = getGraphics(); + try + { + g.setClip(paintArea); + awtComponent.paint(g); + } + finally + { + g.dispose(); + } + } + } + + // This method and its overrides are the only methods in the peers + // that should call awtComponent.update. + protected void updateComponent (PaintEvent event) + { + // Do not call Component.update if the component is not showing or + // if its bounds form a degenerate rectangle. + if (!awtComponent.isShowing() + || (awtComponent.getWidth() < 1 || awtComponent.getHeight() < 1)) + return; + + // Make sure that the paintArea includes the area from the event + // in the case when an application sends PaintEvents directly. + coalescePaintEvent(event); + Rectangle paintArea; + synchronized (this) + { + paintArea = currentPaintArea; + currentPaintArea = null; + } + + if (paintArea != null) + { + Graphics g = getGraphics(); + try + { + g.setClip(paintArea); + awtComponent.update(g); + } + finally + { + g.dispose(); + } + } + } + + public boolean isFocusTraversable () + { + return true; + } + + public Dimension minimumSize () + { + int dim[] = new int[2]; + + gtkWidgetGetPreferredDimensions (dim); + + return new Dimension (dim[0], dim[1]); + } + + public void paint (Graphics g) + { + } + + public Dimension preferredSize () + { + int dim[] = new int[2]; + + gtkWidgetGetPreferredDimensions (dim); + + return new Dimension (dim[0], dim[1]); + } + + public boolean prepareImage (Image image, int width, int height, + ImageObserver observer) + { + return getToolkit().prepareImage(image, width, height, observer); + } + + public void print (Graphics g) + { + g.drawImage( ComponentGraphics.grab( this ), 0, 0, null ); + } + + public void repaint (long tm, int x, int y, int width, int height) + { + if (width < 1 || height < 1) + return; + + if (tm <= 0) + q().postEvent(new PaintEvent(awtComponent, PaintEvent.UPDATE, + new Rectangle(x, y, width, height))); + else + RepaintTimerTask.schedule(tm, x, y, width, height, awtComponent); + } + + /** + * Used for scheduling delayed paint updates on the event queue. + */ + private static class RepaintTimerTask extends TimerTask + { + private static final Timer repaintTimer = new Timer(true); + + private int x, y, width, height; + private Component awtComponent; + + RepaintTimerTask(Component c, int x, int y, int width, int height) + { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.awtComponent = c; + } + + public void run() + { + q().postEvent (new PaintEvent (awtComponent, PaintEvent.UPDATE, + new Rectangle (x, y, width, height))); + } + + static void schedule(long tm, int x, int y, int width, int height, + Component c) + { + repaintTimer.schedule(new RepaintTimerTask(c, x, y, width, height), tm); + } + } + + public void requestFocus () + { + assert false: "Call new requestFocus() method instead"; + } + + public void reshape (int x, int y, int width, int height) + { + setBounds (x, y, width, height); + } + + public void setBackground (Color c) + { + gtkWidgetSetBackground (c.getRed(), c.getGreen(), c.getBlue()); + } + + native void setNativeBounds (int x, int y, int width, int height); + + public void setBounds (int x, int y, int width, int height) + { + int new_x = x; + int new_y = y; + + Component parent = awtComponent.getParent (); + + // Heavyweight components that are children of one or more + // lightweight containers have to be handled specially. Because + // calls to GLightweightPeer.setBounds do nothing, GTK has no + // knowledge of the lightweight containers' positions. So we have + // to add the offsets manually when placing a heavyweight + // component within a lightweight container. The lightweight + // container may itself be in a lightweight container and so on, + // so we need to continue adding offsets until we reach a + // container whose position GTK knows -- that is, the first + // non-lightweight. + Insets i; + while (parent.isLightweight()) + { + i = ((Container) parent).getInsets(); + + new_x += parent.getX() + i.left; + new_y += parent.getY() + i.top; + + parent = parent.getParent(); + } + // We only need to convert from Java to GTK coordinates if we're + // placing a heavyweight component in a Window. + if (parent instanceof Window) + { + GtkWindowPeer peer = (GtkWindowPeer) parent.getPeer (); + // important: we want the window peer's insets here, not the + // window's, since user sub-classes of Window can override + // getInset and we only want to correct for the frame borders, + // not for any user-defined inset values + Insets insets = peer.getInsets (); + + int menuBarHeight = 0; + if (peer instanceof GtkFramePeer) + menuBarHeight = ((GtkFramePeer) peer).getMenuBarHeight (); + + new_x -= insets.left; + new_y -= insets.top; + new_y += menuBarHeight; + } + + setNativeBounds (new_x, new_y, width, height); + + // If the height or width were (or are now) smaller than zero + // then we want to adjust the visibility. + setVisible(awtComponent.isVisible()); + } + + void setCursor () + { + setCursor (awtComponent.getCursor ()); + } + + public void setCursor (Cursor cursor) + { + int x, y; + GtkImage image; + int type = cursor.getType(); + if (cursor instanceof GtkCursor) + { + GtkCursor gtkCursor = (GtkCursor) cursor; + image = gtkCursor.getGtkImage(); + Point hotspot = gtkCursor.getHotspot(); + x = hotspot.x; + y = hotspot.y; + } + else + { + image = null; + x = 0; + y = 0; + } + + if (Thread.currentThread() == GtkMainThread.mainThread) + gtkWidgetSetCursorUnlocked(cursor.getType(), image, x, y); + else + gtkWidgetSetCursor(cursor.getType(), image, x, y); + } + + public void setEnabled (boolean b) + { + gtkWidgetSetSensitive (b); + } + + public void setFont (Font f) + { + // FIXME: This should really affect the widget tree below me. + // Currently this is only handled if the call is made directly on + // a text widget, which implements setFont() itself. + gtkWidgetModifyFont(f.getName(), f.getStyle(), f.getSize()); + } + + public void setForeground (Color c) + { + gtkWidgetSetForeground (c.getRed(), c.getGreen(), c.getBlue()); + } + + public Color getForeground () + { + int rgb[] = gtkWidgetGetForeground (); + return new Color (rgb[0], rgb[1], rgb[2]); + } + + public Color getBackground () + { + int rgb[] = gtkWidgetGetBackground (); + return new Color (rgb[0], rgb[1], rgb[2]); + } + + public native void setVisibleNative (boolean b); + public native void setVisibleNativeUnlocked (boolean b); + + public void setVisible (boolean b) + { + // Only really set visible when component is bigger than zero pixels. + if (b && ! (awtComponent instanceof Window)) + { + Rectangle bounds = awtComponent.getBounds(); + b = (bounds.width > 0) && (bounds.height > 0); + } + + if (Thread.currentThread() == GtkMainThread.mainThread) + setVisibleNativeUnlocked (b); + else + setVisibleNative (b); + } + + public void hide () + { + setVisible (false); + } + + public void show () + { + setVisible (true); + } + + protected void postMouseEvent(int id, long when, int mods, int x, int y, + int clickCount, boolean popupTrigger) + { + // It is important to do the getLocationOnScreen() here, instead + // of using the old MouseEvent constructors, because + // Component.getLocationOnScreen() locks on the AWT lock, which can + // trigger a deadlock. You don't want this. + Point locOnScreen = getLocationOnScreen(); + q().postEvent(new MouseEvent(awtComponent, id, when, mods, x, y, + locOnScreen.x + x, locOnScreen.y + y, + clickCount, popupTrigger, + MouseEvent.NOBUTTON)); + } + + /** + * Callback for component_scroll_cb. + */ + protected void postMouseWheelEvent(int id, long when, int mods, + int x, int y, int clickCount, + boolean popupTrigger, + int type, int amount, int rotation) + { + q().postEvent(new MouseWheelEvent(awtComponent, id, when, mods, + x, y, clickCount, popupTrigger, + type, amount, rotation)); + } + + protected void postExposeEvent (int x, int y, int width, int height) + { + q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT, + new Rectangle (x, y, width, height))); + } + + protected void postKeyEvent (int id, long when, int mods, + int keyCode, char keyChar, int keyLocation) + { + KeyEvent keyEvent = new KeyEvent (awtComponent, id, when, mods, + keyCode, keyChar, keyLocation); + + EventQueue q = q(); + + // Also post a KEY_TYPED event if keyEvent is a key press that + // doesn't represent an action or modifier key. + if (keyEvent.getID () == KeyEvent.KEY_PRESSED + && (!keyEvent.isActionKey () + && keyCode != KeyEvent.VK_SHIFT + && keyCode != KeyEvent.VK_CONTROL + && keyCode != KeyEvent.VK_ALT)) + { + synchronized(q) + { + q.postEvent(keyEvent); + keyEvent = new KeyEvent(awtComponent, KeyEvent.KEY_TYPED, when, + mods, KeyEvent.VK_UNDEFINED, keyChar, + keyLocation); + q.postEvent(keyEvent); + } + } + else + q.postEvent(keyEvent); + } + + /** + * Referenced from native code. + * + * @param id + * @param temporary + */ + protected void postFocusEvent (int id, boolean temporary) + { + q().postEvent (new FocusEvent (awtComponent, id, temporary)); + } + + protected void postItemEvent (Object item, int stateChange) + { + q().postEvent (new ItemEvent ((ItemSelectable)awtComponent, + ItemEvent.ITEM_STATE_CHANGED, + item, stateChange)); + } + + protected void postTextEvent () + { + q().postEvent (new TextEvent (awtComponent, TextEvent.TEXT_VALUE_CHANGED)); + } + + public GraphicsConfiguration getGraphicsConfiguration () + { + // FIXME: The component might be showing on a non-default screen. + GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice dev = env.getDefaultScreenDevice(); + return dev.getDefaultConfiguration(); + } + + public void setEventMask (long mask) + { + // FIXME: just a stub for now. + } + + public boolean isFocusable () + { + return false; + } + + public boolean requestFocus (Component request, boolean temporary, + boolean allowWindowFocus, long time) + { + assert request == awtComponent || isLightweightDescendant(request); + boolean retval = false; + if (gtkWidgetHasFocus()) + { + KeyboardFocusManager kfm = + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + Component currentFocus = kfm.getFocusOwner(); + if (currentFocus == request) + // Nothing to do in this trivial case. + retval = true; + else + { + // Requested component is a lightweight descendant of this one + // or the actual heavyweight. + // Since this (native) component is already focused, we simply + // change the actual focus and be done. + postFocusEvent(FocusEvent.FOCUS_GAINED, temporary); + retval = true; + } + } + else + { + if (gtkWidgetCanFocus()) + { + if (allowWindowFocus) + { + Window window = getWindowFor(request); + GtkWindowPeer wPeer = (GtkWindowPeer) window.getPeer(); + if (! wPeer.gtkWindowHasFocus()) + wPeer.requestWindowFocus(); + } + // Store requested focus component so that the corresponding + // event is dispatched correctly. + gtkWidgetRequestFocus(); + retval = true; + } + } + return retval; + } + + private Window getWindowFor(Component c) + { + Component comp = c; + while (! (comp instanceof Window)) + comp = comp.getParent(); + return (Window) comp; + } + + /** + * Returns true if the component is a direct (== no intermediate + * heavyweights) lightweight descendant of this peer's component. + * + * @param c the component to check + * + * @return true if the component is a direct (== no intermediate + * heavyweights) lightweight descendant of this peer's component + */ + protected boolean isLightweightDescendant(Component c) + { + Component comp = c; + while (comp.getPeer() instanceof LightweightPeer) + comp = comp.getParent(); + return comp == awtComponent; + } + + public boolean isObscured () + { + return false; + } + + public boolean canDetermineObscurity () + { + return false; + } + + public void coalescePaintEvent (PaintEvent e) + { + synchronized (this) + { + Rectangle newRect = e.getUpdateRect(); + if (currentPaintArea == null) + currentPaintArea = newRect; + else + Rectangle.union(currentPaintArea, newRect, currentPaintArea); + } + } + + public void updateCursorImmediately () + { + if (awtComponent.getCursor() != null) + setCursor(awtComponent.getCursor()); + } + + public boolean handlesWheelScrolling () + { + return false; + } + + // Convenience method to create a new volatile image on the screen + // on which this component is displayed. + public VolatileImage createVolatileImage (int width, int height) + { + return new GtkVolatileImage (this, width, height, null); + } + + // Creates buffers used in a buffering strategy. + public void createBuffers (int numBuffers, BufferCapabilities caps) + throws AWTException + { + // numBuffers == 2 implies double-buffering, meaning one back + // buffer and one front buffer. + if (numBuffers == 2) + backBuffer = new GtkVolatileImage(this, awtComponent.getWidth(), + awtComponent.getHeight(), + caps.getBackBufferCapabilities()); + else + throw new AWTException("GtkComponentPeer.createBuffers:" + + " multi-buffering not supported"); + this.caps = caps; + } + + // Return the back buffer. + public Image getBackBuffer () + { + return backBuffer; + } + + // FIXME: flip should be implemented as a fast native operation + public void flip (BufferCapabilities.FlipContents contents) + { + getGraphics().drawImage(backBuffer, + awtComponent.getWidth(), + awtComponent.getHeight(), + null); + + // create new back buffer and clear it to the background color. + if (contents == BufferCapabilities.FlipContents.BACKGROUND) + { + backBuffer = createVolatileImage(awtComponent.getWidth(), + awtComponent.getHeight()); + backBuffer.getGraphics().clearRect(0, 0, + awtComponent.getWidth(), + awtComponent.getHeight()); + } + // FIXME: support BufferCapabilities.FlipContents.PRIOR + } + + // Release the resources allocated to back buffers. + public void destroyBuffers () + { + backBuffer.flush(); + } + + public String toString () + { + return "peer of " + awtComponent.toString(); + } + public Rectangle getBounds() + { + // FIXME: implement + return null; + } + public void reparent(ContainerPeer parent) + { + // FIXME: implement + + } + public void setBounds(int x, int y, int width, int height, int z) + { + // FIXME: implement + setBounds (x, y, width, height); + + } + public boolean isReparentSupported() + { + // FIXME: implement + + return false; + } + public void layout() + { + // FIXME: implement + + } + + public boolean requestFocus(Component lightweightChild, boolean temporary, + boolean focusedWindowChangeAllowed, + long time, sun.awt.CausedFocusEvent.Cause cause) + { + // TODO: Implement this properly and remove the other requestFocus() + // methods. + return true; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java new file mode 100644 index 000000000..b7eacb9f6 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkContainerPeer.java @@ -0,0 +1,138 @@ +/* GtkContainerPeer.java -- Implements ContainerPeer with GTK + Copyright (C) 1998, 1999, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Font; +import java.awt.Insets; +import java.awt.peer.ContainerPeer; + +public class GtkContainerPeer extends GtkComponentPeer + implements ContainerPeer +{ + Container c; + + public GtkContainerPeer(Container c) + { + super (c); + this.c = c; + } + + public void beginValidate () + { + } + + public void endValidate () + { + } + + public Insets getInsets() + { + return insets; + } + + public Insets insets() + { + return getInsets (); + } + + public void setBounds (int x, int y, int width, int height) + { + super.setBounds (x, y, width, height); + } + + public void setFont(Font f) + { + super.setFont(f); + Component[] components = ((Container) awtComponent).getComponents(); + for (int i = 0; i < components.length; i++) + { + if (components[i].isLightweight ()) + components[i].setFont (f); + else + { + GtkComponentPeer peer = (GtkComponentPeer) components[i].getPeer(); + if (peer != null && ! peer.awtComponent.isFontSet()) + peer.setFont(f); + } + } + } + + public void beginLayout () { } + public void endLayout () { } + public boolean isPaintPending () { return false; } + + public void setBackground (Color c) + { + super.setBackground(c); + + Object components[] = ((Container) awtComponent).getComponents(); + for (int i = 0; i < components.length; i++) + { + Component comp = (Component) components[i]; + + // If the child's background has not been explicitly set yet, + // it should inherit this container's background. This makes the + // child component appear as if it has a transparent background. + // Note that we do not alter the background property of the child, + // but only repaint the child with the parent's background color. + if (!comp.isBackgroundSet() && comp.getPeer() != null) + comp.getPeer().setBackground(c); + } + } + + public boolean isRestackSupported() + { + // FIXME: implement + return false; + } + + public void cancelPendingPaint(int x, int y, int width, int height) + { + // FIXME: implement + } + + public void restack() + { + //FIXME: implement + + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkCursor.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCursor.java new file mode 100644 index 000000000..e382d6331 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkCursor.java @@ -0,0 +1,72 @@ +/* GtkCursor.java -- Simple wrapper for custom cursor. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Cursor; +import java.awt.Image; +import java.awt.Point; + +/** + * Simple wrapper for custom Cursor. + */ +public class GtkCursor extends Cursor +{ + private final GtkImage image; + private final Point hotspot; + + GtkCursor(Image image, Point hotspot, String name) + { + super(name); + if (image instanceof GtkImage) + this.image = (GtkImage) image; + else + this.image = new GtkImage(image.getSource()); + this.hotspot = hotspot; + } + + GtkImage getGtkImage() + { + return image; + } + + Point getHotspot() + { + return hotspot; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkDialogPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkDialogPeer.java new file mode 100644 index 000000000..3393eb9d0 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkDialogPeer.java @@ -0,0 +1,63 @@ +/* GtkDialogPeer.java -- Implements DialogPeer with GTK + Copyright (C) 1998, 1999, 2002, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Dialog; +import java.awt.peer.DialogPeer; + +public class GtkDialogPeer extends GtkWindowPeer + implements DialogPeer +{ + public GtkDialogPeer (Dialog dialog) + { + super (dialog); + } + + void create () + { + Dialog dialog = (Dialog) awtComponent; + + // Create a decorated dialog window. + create (GDK_WINDOW_TYPE_HINT_DIALOG, !((Dialog) awtComponent).isUndecorated ()); + + gtkWindowSetModal (dialog.isModal ()); + setTitle (dialog.getTitle ()); + setResizable (dialog.isResizable ()); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkEmbeddedWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkEmbeddedWindowPeer.java new file mode 100644 index 000000000..0533d2759 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkEmbeddedWindowPeer.java @@ -0,0 +1,73 @@ +/* GtkEmbeddedWindowPeer.java -- Implements EmbeddedWindowPeer using a + GtkPlug + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import gnu.java.awt.EmbeddedWindow; +import gnu.java.awt.peer.EmbeddedWindowPeer; + +public class GtkEmbeddedWindowPeer extends GtkFramePeer + implements EmbeddedWindowPeer +{ + native void create (long socket_id); + + void create () + { + create (((EmbeddedWindow) awtComponent).getHandle ()); + } + + native void construct (long socket_id); + + // FIXME: embed doesn't work right now, though I believe it should. + // This means that you can't call setVisible (true) on an + // EmbeddedWindow before calling setHandle with a valid handle. The + // problem is that somewhere after the call to + // GtkEmbeddedWindow.create and before the call to + // GtkEmbeddedWindow.construct, the GtkPlug peer is being realized. + // GtkSocket silently fails to embed an already-realized GtkPlug. + public void embed (long handle) + { + construct (handle); + } + + public GtkEmbeddedWindowPeer (EmbeddedWindow w) + { + super (w); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java new file mode 100644 index 000000000..cddc530fd --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFileDialogPeer.java @@ -0,0 +1,229 @@ +/* GtkFileDialogPeer.java -- Implements FileDialogPeer with GTK + Copyright (C) 1998, 1999, 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Dialog; +import java.awt.FileDialog; +import java.awt.event.PaintEvent; +import java.awt.peer.FileDialogPeer; +import java.io.File; +import java.io.FilenameFilter; + +public class GtkFileDialogPeer extends GtkDialogPeer implements FileDialogPeer +{ + static final String FS = System.getProperty("file.separator"); + + private String currentFile = null; + private String currentDirectory = null; + private FilenameFilter filter; + + native void create (GtkContainerPeer parent, int mode); + native void connectSignals (); + native void nativeSetFile (String file); + public native String nativeGetDirectory(); + public native void nativeSetDirectory(String directory); + native void nativeSetFilenameFilter (FilenameFilter filter); + + public void create() + { + create((GtkContainerPeer) awtComponent.getParent().getPeer(), + ((FileDialog) awtComponent).getMode()); + + FileDialog fd = (FileDialog) awtComponent; + + nativeSetDirectory(System.getProperty("user.dir")); + setDirectory(fd.getDirectory()); + setFile(fd.getFile()); + + FilenameFilter filter = fd.getFilenameFilter(); + if (filter != null) + setFilenameFilter(filter); + } + + public GtkFileDialogPeer (FileDialog fd) + { + super (fd); + } + + void setComponentBounds () + { + if (awtComponent.getHeight () == 0 + && awtComponent.getWidth () == 0) + { + int[] dims = new int[2]; + gtkWidgetGetPreferredDimensions (dims); + + if (dims[0] != awtComponent.getWidth() + || dims[1] != awtComponent.getHeight()) + awtComponent.setSize(dims[0], dims[1]); + } + super.setComponentBounds (); + } + + public void setFile (String fileName) + { + /* If nothing changed do nothing. This usually happens because + the only way we have to set the file name in FileDialog is by + calling its SetFile which will call us back. */ + if ((fileName == null && currentFile == null) + || (fileName != null && fileName.equals (currentFile))) + return; + + if (fileName == null || fileName.equals ("")) + { + currentFile = ""; + nativeSetFile (""); + return; + } + + // GtkFileChooser requires absolute filenames. If the given filename + // is not absolute, let's construct it based on current directory. + currentFile = fileName; + if (fileName.indexOf(FS) == 0) + nativeSetFile(fileName); + else + nativeSetFile(nativeGetDirectory() + FS + fileName); + } + + public void setDirectory (String directory) + { + /* If nothing changed so nothing. This usually happens because + the only way we have to set the directory in FileDialog is by + calling its setDirectory which will call us back. */ + if ((directory == null && currentDirectory == null) + || (directory != null && directory.equals(currentDirectory))) + return; + + if (directory == null || directory.equals("")) + { + currentDirectory = FS; + nativeSetDirectory(FS); + return; + } + + // GtkFileChooser requires absolute directory names. If the given directory + // name is not absolute, construct it based on current directory if it is not + // null. Otherwise, use FS. + currentDirectory = directory; + if (directory.indexOf(FS) == 0) + nativeSetDirectory(directory); + else + nativeSetDirectory(nativeGetDirectory() + FS + directory); + } + + public void setFilenameFilter (FilenameFilter filter) + { + this.filter = filter; + nativeSetFilenameFilter(filter); + } + + /* This method interacts with the native callback function of the + same name. The native function will extract the filename from the + GtkFileFilterInfo object and send it to this method, which will + in turn call the filter's accept() method and give back the return + value. */ + // called back by native side: filename_filter_cb + boolean filenameFilterCallback (String fullname) + { + String filename = fullname.substring(fullname.lastIndexOf(FS) + 1); + String dirname = fullname.substring(0, fullname.lastIndexOf(FS)); + File dir = new File(dirname); + return filter.accept(dir, filename); + } + + // Sun does not call FileDialog.update. + protected void updateComponent (PaintEvent event) + { + // Override GtkComponetPeer.updateComponent to do nothing. + } + + // called back by native side: handle_response_cb + // only called from the GTK thread + void gtkHideFileDialog () + { + // hide calls back the peer's setVisible method, so locking is a + // problem. + ((Dialog) awtComponent).hide(); + } + + // called back by native side: handle_response_cb + void gtkDisposeFileDialog () + { + ((Dialog) awtComponent).dispose(); + } + + // Callback to set the file and directory values when the user is finished + // with the dialog. + // called back by native side: handle_response_cb + void gtkSetFilename (String fileName) + { + FileDialog fd = (FileDialog) awtWidget; + if (fileName == null) + { + currentFile = null; + fd.setFile(null); + return; + } + + int sepIndex = fileName.lastIndexOf (FS); + if (sepIndex < 0) + { + /* This should never happen on Unix (all paths start with '/') */ + currentFile = fileName; + } + else + { + if (fileName.length() > (sepIndex + 1)) + { + String fn = fileName.substring (sepIndex + 1); + currentFile = fn; + } + else + { + currentFile = null; + } + + String dn = fileName.substring (0, sepIndex + 1); + currentDirectory = dn; + fd.setDirectory(dn); + } + + fd.setFile (currentFile); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java new file mode 100644 index 000000000..a36854ce0 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkFramePeer.java @@ -0,0 +1,254 @@ +/* GtkFramePeer.java -- Implements FramePeer with GTK + Copyright (C) 1999, 2002, 2004, 2006, 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Frame; +import java.awt.Image; +import java.awt.MenuBar; +import java.awt.Rectangle; +import java.awt.peer.FramePeer; +import java.awt.peer.MenuBarPeer; + +public class GtkFramePeer extends GtkWindowPeer + implements FramePeer +{ + private int menuBarHeight; + private MenuBarPeer menuBar; + native int getMenuBarHeight (MenuBarPeer bar); + native void setMenuBarWidthUnlocked (MenuBarPeer bar, int width); + native void setMenuBarWidth (MenuBarPeer bar, int width); + native void setMenuBarPeer (MenuBarPeer bar); + native void removeMenuBarPeer (); + native void gtkFixedSetVisible (boolean visible); + + private native void maximize(); + private native void unmaximize(); + private native void iconify(); + private native void deiconify(); + + int getMenuBarHeight () + { + return menuBar == null ? 0 : getMenuBarHeight (menuBar); + } + + public void setMenuBar (MenuBar bar) + { + if (bar == null && menuBar != null) + { + // We're removing the menubar. + gtkFixedSetVisible (false); + menuBar = null; + removeMenuBarPeer (); + insets.top -= menuBarHeight; + menuBarHeight = 0; + // if component has already been validated, we need to revalidate. + // otherwise, it will be validated when it is shown. + if (awtComponent.isValid()) + awtComponent.validate (); + gtkFixedSetVisible (true); + } + else if (bar != null && menuBar == null) + { + // We're adding a menubar where there was no menubar before. + gtkFixedSetVisible (false); + menuBar = (MenuBarPeer) bar.getPeer(); + setMenuBarPeer (menuBar); + int menuBarWidth = + awtComponent.getWidth () - insets.left - insets.right; + if (menuBarWidth > 0) + setMenuBarWidth (menuBar, menuBarWidth); + menuBarHeight = getMenuBarHeight (); + insets.top += menuBarHeight; + // if component has already been validated, we need to revalidate. + // otherwise, it will be validated when it is shown. + if (awtComponent.isValid()) + awtComponent.validate (); + gtkFixedSetVisible (true); + } + else if (bar != null && menuBar != null) + { + // We're swapping the menubar. + gtkFixedSetVisible (false); + removeMenuBarPeer(); + int oldHeight = menuBarHeight; + int menuBarWidth = + awtComponent.getWidth () - insets.left - insets.right; + menuBar = (MenuBarPeer) bar.getPeer (); + setMenuBarPeer (menuBar); + if (menuBarWidth > 0) + setMenuBarWidth (menuBar, menuBarWidth); + menuBarHeight = getMenuBarHeight (); + if (oldHeight != menuBarHeight) + { + insets.top += (menuBarHeight - oldHeight); + awtComponent.validate (); + } + gtkFixedSetVisible (true); + } + } + + public void setBounds (int x, int y, int width, int height) + { + int menuBarWidth = width - insets.left - insets.right; + if (menuBar != null && menuBarWidth > 0) + setMenuBarWidth (menuBar, menuBarWidth); + + super.setBounds(x, y, width, height + menuBarHeight); + } + + public void setResizable (boolean resizable) + { + // Call setSize; otherwise when resizable is changed from true to + // false the frame will shrink to the dimensions it had before it + // was resizable. + setSize (awtComponent.getWidth() - insets.left - insets.right, + awtComponent.getHeight() - insets.top - insets.bottom + + menuBarHeight); + gtkWindowSetResizable (resizable); + } + + protected void postInsetsChangedEvent (int top, int left, + int bottom, int right) + { + insets.top = top + menuBarHeight; + insets.left = left; + insets.bottom = bottom; + insets.right = right; + } + + public GtkFramePeer (Frame frame) + { + super (frame); + } + + void create () + { + // Create a normal decorated window. + create (GDK_WINDOW_TYPE_HINT_NORMAL, + !((Frame) awtComponent).isUndecorated ()); + + Frame frame = (Frame) awtComponent; + + setMenuBar (frame.getMenuBar ()); + + setTitle (frame.getTitle ()); + gtkWindowSetResizable (frame.isResizable ()); + setIconImage(frame.getIconImage()); + } + + native void nativeSetIconImage (GtkImage image); + + public void setIconImage (Image image) + { + if (image != null) + { + GtkImage gtkImage; + if (image instanceof GtkImage) + gtkImage = (GtkImage) image; + else + gtkImage = new GtkImage(image.getSource()); + + if (gtkImage.isLoaded && ! gtkImage.errorLoading) + nativeSetIconImage(gtkImage); + } + } + + protected void postConfigureEvent (int x, int y, int width, int height) + { + if (menuBar != null && width > 0) + setMenuBarWidthUnlocked (menuBar, width); + + // Since insets.top already includes the MenuBar's height, we need + // to subtract the MenuBar's height from the top inset. + int frame_height = height - menuBarHeight; + + // Likewise, since insets.top includes the MenuBar height, we need + // to add back the MenuBar height to the frame's y position. If + // no MenuBar exists in this frame, the MenuBar height will be 0. + int frame_y = y + menuBarHeight; + + super.postConfigureEvent(x, frame_y, width, frame_height); + } + + public int getState () + { + return windowState; + } + + public void setState (int state) + { + switch (state) + { + case Frame.NORMAL: + if ((windowState & Frame.ICONIFIED) != 0) + deiconify(); + if ((windowState & Frame.MAXIMIZED_BOTH) != 0) + unmaximize(); + break; + case Frame.ICONIFIED: + iconify(); + break; + case Frame.MAXIMIZED_BOTH: + maximize(); + } + } + + public void setMaximizedBounds (Rectangle r) + { + + } + public void setBoundsPrivate(int x, int y, int width, int height) + { + // TODO Auto-generated method stub + + } + + public boolean requestWindowFocus() + { + // TODO Auto-generated method stub + return false; + } + + public Rectangle getBoundsPrivate() + { + // TODO: Implement this properly. + throw new InternalError("Not yet implemented"); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkGenericPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkGenericPeer.java new file mode 100644 index 000000000..1b2c07b5d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkGenericPeer.java @@ -0,0 +1,145 @@ +/* GtkGenericPeer.java - Has a hashcode. Yuck. + Copyright (C) 1998, 1999, 2002, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; + +import gnu.classpath.Pointer; + +public class GtkGenericPeer +{ + // Used by Native State Association (NSA) functions to map + // gtk_widget to peer object. + final int native_state = getUniqueInteger (); + + // Next native state value we will assign. + private static int next_native_state = 0; + + // The widget or other java-side object we wrap. + protected final Object awtWidget; + + /** + * The pointer to the native GTK widget. + * + * This field is manipulated by native code. Don't change or remove + * without adjusting the native code. + */ + private Pointer widget; + + /** + * The pointer to the global reference to this object. The native + * code creates a JNI global reference of the peer object to be able + * to pass it to the event callbacks. It gets stored here, so that + * we can later delete it in the dispose() method. + * + * This field is manipulated by native code. Don't change or remove + * without adjusting the native code. + */ + private Pointer globalRef; + + /** + * We initialize the field IDs that are used by native code here because + * these remain valid until a class gets unloaded. + */ + static + { + GtkToolkit.initializeGlobalIDs(); + initIDs(); + } + + /** + * Initializes the field IDs that are used by the native code. + */ + private static native void initIDs(); + + /** + * Dispose of our native state. Calls gtk_widget_destroy on the + * native widget and removes the awtWidget from the native state + * tables. Should be overridden by subclasses if this is not (all) + * that needs to be done. + */ + public native void dispose (); + + static EventQueue q () + { + return Toolkit.getDefaultToolkit ().getSystemEventQueue (); + } + + protected GtkGenericPeer (Object awtWidget) + { + this.awtWidget = awtWidget; + } + + protected void postActionEvent (String command, int mods) + { + q().postEvent (new ActionEvent (awtWidget, ActionEvent.ACTION_PERFORMED, + command, mods)); + } + + // Return a unique integer for use in the native state mapping + // code. We can't use a hash code since that is not guaranteed to + // be unique. + static synchronized int getUniqueInteger () + { + // Let's assume this will never wrap. + return next_native_state++; + } + + /** + * Helper method to set Font for Gtk Widget. + */ + protected void gtkWidgetModifyFont(Font f) + { + gtkWidgetModifyFont(f.getName(), f.getStyle(), f.getSize()); + } + + /** + * Sets font for this Gtk Widget. Should be overridden by peers which + * are composed of different widgets or are contained in bins. + */ + protected native void gtkWidgetModifyFont(String name, int style, int size); + + static void printCurrentThread () + { + System.out.println ("gtkgenericpeer, thread: " + Thread.currentThread ()); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java new file mode 100644 index 000000000..b0a5aa0b1 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImage.java @@ -0,0 +1,541 @@ +/* GtkImage.java + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Graphics; +import java.awt.Image; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.MemoryImageSource; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.io.File; +import java.io.IOException; +import java.util.Hashtable; +import java.util.Vector; +import java.io.ByteArrayOutputStream; +import java.io.BufferedInputStream; +import java.net.URL; +import gnu.classpath.Pointer; + +/** + * GtkImage - wraps a GdkPixbuf. + * + * A GdkPixbuf is 'on-screen' and the gdk cannot draw to it, + * this is used for the other constructors (and other createImage methods), and + * corresponds to the Image implementations returned by the Toolkit.createImage + * methods, and is basically immutable. + * + * @author Sven de Marothy + */ +public class GtkImage extends Image +{ + int width = -1, height = -1; + + /** + * Properties. + */ + Hashtable props; + + /** + * Loaded or not flag, for asynchronous compatibility. + */ + boolean isLoaded; + + /** + * Pointer to the GdkPixbuf - + * don't change the name without changing the native code. + */ + Pointer pixbuf; + + /** + * Observer queue. + */ + Vector observers; + + /** + * Error flag for loading. + */ + boolean errorLoading; + + /** + * Original source, if created from an ImageProducer. + */ + ImageProducer source; + + /* + * The 32-bit AABBGGRR format the GDK uses. + */ + static ColorModel nativeModel = new DirectColorModel(32, + 0x000000FF, + 0x0000FF00, + 0x00FF0000, + 0xFF000000); + + /** + * The singleton GtkImage that is returned on errors by GtkToolkit. + */ + private static GtkImage errorImage; + + /** + * Lock that should be held for all gdkpixbuf operations. We don't use + * the global gdk_threads_enter/leave functions in most places since + * most gdkpixbuf operations can be done in parallel to drawing and + * manipulating gtk widgets. + */ + static Object pixbufLock = new Object(); + + /** + * Allocate a PixBuf from a given ARGB32 buffer pointer. + */ + private native void initFromBuffer( long bufferPointer ); + + /** + * Returns a copy of the pixel data as a java array. + * Should be called with the pixbufLock held. + */ + native int[] getPixels(); + + /** + * Sets the pixel data from a java array. + * Should be called with the pixbufLock held. + */ + private native void setPixels(int[] pixels); + + /** + * Loads an image using gdk-pixbuf from a file. + * Should be called with the pixbufLock held. + */ + private native boolean loadPixbuf(String name); + + /** + * Loads an image using gdk-pixbuf from data. + * Should be called with the pixbufLock held. + */ + private native boolean loadImageFromData(byte[] data); + + /** + * Allocates a Gtk Pixbuf + * Should be called with the pixbufLock held. + */ + private native void createPixbuf(); + + /** + * Frees the above. + * Should be called with the pixbufLock held. + */ + private native void freePixbuf(); + + /** + * Sets the pixbuf to scaled copy of src image. hints are rendering hints. + * Should be called with the pixbufLock held. + */ + private native void createScaledPixbuf(GtkImage src, int hints); + + /** + * Constructs a GtkImage from an ImageProducer. Asynchronity is handled in + * the following manner: + * A GtkImageConsumer gets the image data, and calls setImage() when + * completely finished. The GtkImage is not considered loaded until the + * GtkImageConsumer is completely finished. We go for all "all or nothing". + */ + public GtkImage (ImageProducer producer) + { + isLoaded = false; + observers = new Vector(); + source = producer; + errorLoading = false; + source.startProduction(new GtkImageConsumer(this, source)); + } + + /** + * Constructs a blank GtkImage. This is called when + * GtkToolkit.createImage (String) is called with an empty string + * argument (""). A blank image is loaded immediately upon + * construction and has width -1 and height -1. + */ + public GtkImage () + { + isLoaded = true; + observers = null; + props = new Hashtable(); + errorLoading = false; + } + + /** + * Constructs a GtkImage by loading a given file. + * + * @throws IllegalArgumentException if the image could not be loaded. + */ + public GtkImage (String filename) + { + File f = new File(filename); + try + { + String path = f.getCanonicalPath(); + synchronized(pixbufLock) + { + if (loadPixbuf(f.getCanonicalPath()) != true) + throw new IllegalArgumentException("Couldn't load image: " + + filename); + } + } + catch(IOException e) + { + IllegalArgumentException iae; + iae = new IllegalArgumentException("Couldn't load image: " + + filename); + iae.initCause(e); + throw iae; + } + + isLoaded = true; + observers = null; + props = new Hashtable(); + } + + /** + * Constructs a GtkImage from a byte array of an image file. + * + * @throws IllegalArgumentException if the image could not be + * loaded. + */ + public GtkImage (byte[] data) + { + synchronized(pixbufLock) + { + if (loadImageFromData (data) != true) + throw new IllegalArgumentException ("Couldn't load image."); + } + + isLoaded = true; + observers = null; + props = new Hashtable(); + errorLoading = false; + } + + /** + * Constructs a GtkImage from a URL. May result in an error image. + */ + public GtkImage (URL url) + { + isLoaded = false; + observers = new Vector(); + errorLoading = false; + if( url == null) + return; + ByteArrayOutputStream baos = new ByteArrayOutputStream (5000); + try + { + BufferedInputStream bis = new BufferedInputStream (url.openStream()); + + byte[] buf = new byte[5000]; + int n = 0; + + while ((n = bis.read(buf)) != -1) + baos.write(buf, 0, n); + bis.close(); + } + catch(IOException e) + { + throw new IllegalArgumentException ("Couldn't load image."); + } + byte[] array = baos.toByteArray(); + synchronized(pixbufLock) + { + if (loadImageFromData(array) != true) + throw new IllegalArgumentException ("Couldn't load image."); + } + + isLoaded = true; + observers = null; + props = new Hashtable(); + } + + /** + * Constructs a scaled version of the src bitmap, using the GDK. + */ + private GtkImage (GtkImage src, int width, int height, int hints) + { + this.width = width; + this.height = height; + props = new Hashtable(); + isLoaded = true; + observers = null; + + // Use the GDK scaling method. + synchronized(pixbufLock) + { + createScaledPixbuf(src, hints); + } + } + + /** + * Package private constructor to create a GtkImage from a given + * PixBuf pointer. + */ + GtkImage (Pointer pixbuf) + { + this.pixbuf = pixbuf; + synchronized(pixbufLock) + { + createFromPixbuf(); + } + isLoaded = true; + observers = null; + props = new Hashtable(); + } + + /** + * Wraps a buffer with a GtkImage. + * + * @param bufferPointer a pointer to an ARGB32 buffer + */ + GtkImage(int width, int height, long bufferPointer) + { + this.width = width; + this.height = height; + props = new Hashtable(); + isLoaded = true; + observers = null; + initFromBuffer( bufferPointer ); + } + + /** + * Returns an empty GtkImage with the errorLoading flag set. + * Called from GtkToolKit when some error occured, but an image needs + * to be returned anyway. + */ + static synchronized GtkImage getErrorImage() + { + if (errorImage == null) + { + errorImage = new GtkImage(); + errorImage.errorLoading = true; + } + return errorImage; + } + + /** + * Native helper function for constructor that takes a pixbuf Pointer. + * Should be called with the pixbufLock held. + */ + private native void createFromPixbuf(); + + /** + * Callback from the image consumer. + */ + public void setImage(int width, int height, + int[] pixels, Hashtable properties) + { + this.width = width; + this.height = height; + props = (properties != null) ? properties : new Hashtable(); + + if (width <= 0 || height <= 0 || pixels == null) + { + errorLoading = true; + return; + } + + synchronized(pixbufLock) + { + createPixbuf(); + setPixels(pixels); + } + isLoaded = true; + deliver(); + } + + // java.awt.Image methods //////////////////////////////////////////////// + + public synchronized int getWidth (ImageObserver observer) + { + if (addObserver(observer)) + return -1; + + return width; + } + + public synchronized int getHeight (ImageObserver observer) + { + if (addObserver(observer)) + return -1; + + return height; + } + + public synchronized Object getProperty (String name, ImageObserver observer) + { + if (addObserver(observer)) + return UndefinedProperty; + + Object value = props.get (name); + return (value == null) ? UndefinedProperty : value; + } + + /** + * Returns the source of this image. + */ + public ImageProducer getSource () + { + if (!isLoaded) + return null; + + int[] pixels; + synchronized (pixbufLock) + { + if (!errorLoading) + pixels = getPixels(); + else + return null; + } + return new MemoryImageSource(width, height, nativeModel, pixels, + 0, width); + } + + /** + * Does nothing. Should not be called. + */ + public Graphics getGraphics () + { + throw new IllegalAccessError("This method only works for off-screen" + +" Images."); + } + + /** + * Returns a scaled instance of this pixbuf. + */ + public Image getScaledInstance(int width, + int height, + int hints) + { + if (width <= 0 || height <= 0) + throw new IllegalArgumentException("Width and height of scaled bitmap" + + "must be >= 0"); + + return new GtkImage(this, width, height, hints); + } + + /** + * If the image is loaded and comes from an ImageProducer, + * regenerate the image from there. + * + * I have no idea if this is ever actually used. Since GtkImage can't be + * instantiated directly, how is the user to know if it was created from + * an ImageProducer or not? + */ + public synchronized void flush () + { + if (isLoaded && source != null) + { + observers = new Vector(); + isLoaded = false; + synchronized(pixbufLock) + { + freePixbuf(); + } + source.startProduction(new GtkImageConsumer(this, source)); + } + } + + public void finalize() + { + if (isLoaded) + { + synchronized(pixbufLock) + { + freePixbuf(); + } + } + } + + /** + * Returns the image status, used by GtkToolkit + */ + public int checkImage (ImageObserver observer) + { + if (addObserver(observer)) + { + if (errorLoading == true) + return ImageObserver.ERROR; + else + return 0; + } + + return ImageObserver.ALLBITS | ImageObserver.WIDTH | ImageObserver.HEIGHT; + } + + + // Private methods //////////////////////////////////////////////// + + /** + * Delivers notifications to all queued observers. + */ + private void deliver() + { + int flags = ImageObserver.HEIGHT | + ImageObserver.WIDTH | + ImageObserver.PROPERTIES | + ImageObserver.ALLBITS; + + if (observers != null) + for(int i=0; i < observers.size(); i++) + ((ImageObserver)observers.elementAt(i)).imageUpdate(this, flags, 0, 0, + width, height); + + observers = null; + } + + /** + * Adds an observer, if we need to. + * @return true if an observer was added. + */ + private boolean addObserver(ImageObserver observer) + { + if (!isLoaded) + { + if(observer != null) + if (!observers.contains (observer)) + observers.addElement (observer); + return true; + } + return false; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java new file mode 100644 index 000000000..65cae7a89 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkImageConsumer.java @@ -0,0 +1,169 @@ +/* GtkImageConsumer.java + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.image.ColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageProducer; +import java.awt.image.MemoryImageSource; +import java.nio.ByteOrder; +import java.util.Hashtable; + +/** + * Helper class to GtkImage. Sits and gathers pixels for a GtkImage and then + * calls GtkImage.setImage(). + * + * @author Sven de Marothy + */ +public class GtkImageConsumer implements ImageConsumer +{ + private GtkImage target; + private int width, height; + private Hashtable properties; + private int[] pixelCache = null; + private ImageProducer source; + + public GtkImageConsumer(GtkImage target, ImageProducer source) + { + this.target = target; + this.source = source; + } + + public synchronized void imageComplete (int status) + { + // we need to reuse the pixel cache for memory image sources since + // a memory image's backing array can be updated "live". + if (!(source instanceof MemoryImageSource)) + source.removeConsumer(this); + target.setImage(width, height, pixelCache, properties); + } + + public synchronized void setColorModel (ColorModel model) + { + // This method is to inform on what the most used color model + // in the image is, for optimization reasons. We ignore this + // information. + } + + public synchronized void setDimensions (int width, int height) + { + pixelCache = new int[width*height]; + + this.width = width; + this.height = height; + } + + public synchronized void setHints (int flags) + { + // This method informs us in which order the pixels are + // delivered, for progressive-loading support, etc. + // Since we wait until it's all loaded, we can ignore the hints. + } + + public synchronized void setPixels (int x, int y, int width, int height, + ColorModel cm, byte[] pixels, + int offset, int scansize) + { + setPixels (x, y, width, height, cm, convertPixels (pixels), offset, + scansize); + } + + public synchronized void setPixels (int x, int y, int width, int height, + ColorModel cm, int[] pixels, + int offset, int scansize) + { + if (pixelCache == null) + return; // Not sure this should ever happen. + + if (cm.equals(GtkImage.nativeModel)) + for (int i = 0; i < height; i++) + System.arraycopy (pixels, offset + (i * scansize), + pixelCache, (y + i) * this.width + x, + width); + else + { + if (ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN) + { + for (int i = 0; i < height; i++) + for (int j = 0; j < width; j++) + { + // get in RRGGBBAA and convert to AARRGGBB + int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]); + int a = ((pix & 0xFF000000) >> 24) & 0xFF; + int rgb = (pix & 0x00FFFFFF) << 8; + pix = rgb | a; + pixelCache[(y + i) * this.width + x + j] = pix; + } + } + else + { + for (int i = 0; i < height; i++) + for (int j = 0; j < width; j++) + { + // get in AARRGGBB and convert to AABBGGRR + int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]); + byte b = (byte)(pix & 0xFF); + byte r = (byte)(((pix & 0x00FF0000) >> 16) & 0xFF); + pix &= 0xFF00FF00; + pix |= ((b & 0xFF) << 16); + pix |= (r & 0xFF); + pixelCache[(y + i) * this.width + x + j] = pix; + } + } + } + } + + /** + * This is an old method, no idea if it's correct. + */ + private int[] convertPixels (byte[] pixels) + { + int ret[] = new int[pixels.length]; + + for (int i = 0; i < pixels.length; i++) + ret[i] = pixels[i] & 0xFF; + + return ret; + } + + public synchronized void setProperties (Hashtable props) + { + this.properties = props; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java new file mode 100644 index 000000000..0bdacbf33 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkLabelPeer.java @@ -0,0 +1,102 @@ +/* GtkLabelPeer.java -- Implements LabelPeer with GTK + Copyright (C) 1998, 1999, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Label; +import java.awt.peer.LabelPeer; + +// A composite widget. GtkLabels have transparent backgrounds. An +// AWT Label is opaque. To compensate, a GtkLabelPeer is a GtkLabel +// packed in a GtkEventBox. +public class GtkLabelPeer extends GtkComponentPeer + implements LabelPeer +{ + native void create (String text, float alignment); + + /** + * Overridden to set the Font of the label inside the gtk_event_box. + */ + protected native void gtkWidgetModifyFont(String name, int style, int size); + + native void nativeSetAlignment (float alignment); + + public native void setNativeText(String text); + native void setNativeBounds (int x, int y, int width, int height); + + // Because this is a composite widget, we need to retrieve the + // GtkLabel's preferred dimensions, not the enclosing GtkEventBox's. + native void gtkWidgetGetPreferredDimensions (int[] dim); + + void create () + { + Label label = (Label) awtComponent; + create (label.getText (), getGtkAlignment (label.getAlignment ())); + } + + public void setText(String text) + { + if (text != null) + setNativeText(text); + } + + public GtkLabelPeer (Label l) + { + super (l); + } + + public void setAlignment (int alignment) + { + nativeSetAlignment (getGtkAlignment (alignment)); + } + + float getGtkAlignment (int alignment) + { + switch (alignment) + { + case Label.LEFT: + return 0.0f; + case Label.CENTER: + return 0.5f; + case Label.RIGHT: + return 1.0f; + } + + return 0.0f; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java new file mode 100644 index 000000000..b1cc6e522 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkListPeer.java @@ -0,0 +1,187 @@ +/* GtkListPeer.java -- Implements ListPeer with GTK + Copyright (C) 1998, 1999, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.AWTEvent; +import java.awt.Dimension; +import java.awt.FontMetrics; +import java.awt.List; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.ListPeer; + +public class GtkListPeer extends GtkComponentPeer + implements ListPeer +{ + void create () + { + List list = (List) awtComponent; + + create (list.getRows ()); + + setMultipleMode (list.isMultipleMode ()); + } + + native void create (int rows); + native void connectSignals (); + + /** + * Overridden to set the Font of the text insode the gtk_scrolled_window. + */ + protected native void gtkWidgetModifyFont (String name, int style, int size); + + native void gtkWidgetRequestFocus (); + + native void getSize (int rows, int visibleRows, int dims[]); + + public GtkListPeer (List list) + { + super (list); + + setMultipleMode (list.isMultipleMode ()); + + if (list.getItemCount () > 0) + append (list.getItems ()); + } + + native void append (String items[]); + + public native void add (String item, int index); + + public void addItem (String item, int index) + { + add (item, index); + } + + public void clear () + { + removeAll (); + } + + public native void delItems (int start, int end); + public native void deselect (int index); + + public Dimension getMinimumSize (int rows) + { + return minimumSize (rows); + } + + public Dimension getPreferredSize (int rows) + { + return preferredSize (rows); + } + + public native int[] getSelectedIndexes (); + public native void makeVisible (int index); + + public Dimension minimumSize (int rows) + { + int dims[] = new int[2]; + + int visibleRows = ((List) awtComponent).getRows(); + getSize (rows, visibleRows, dims); + return new Dimension (dims[0], dims[1]); + } + + public Dimension preferredSize (int rows) + { + // getSize returns the minimum size of the list. + // The width is too narrow for a typical list. + List l = (List) awtComponent; + Dimension d = getMinimumSize(); + FontMetrics fm = l.getFontMetrics(l.getFont()); + return new Dimension(d.width + fm.stringWidth("1234567890"), d.height); + } + + public void removeAll () + { + delItems (0, -1); + } + + public native void select (int index); + public native void setMultipleMode (boolean b); + + public void setMultipleSelections (boolean b) + { + setMultipleMode (b); + } + + public void handleEvent (AWTEvent e) + { + if (e.getID () == MouseEvent.MOUSE_CLICKED && isEnabled ()) + { + // Only generate the ActionEvent on the second click of a + // multiple click. + MouseEvent me = (MouseEvent) e; + if (!me.isConsumed () + && (me.getModifiersEx () & MouseEvent.BUTTON1_DOWN_MASK) != 0 + && me.getClickCount() == 2) + { + String selectedItem = ((List) awtComponent).getSelectedItem (); + + // Double-click only generates an Action event if + // something is selected. + if (selectedItem != null) + postActionEvent (((List) awtComponent).getSelectedItem (), + me.getModifiersEx ()); + } + } + + if (e.getID () == KeyEvent.KEY_PRESSED) + { + KeyEvent ke = (KeyEvent) e; + if (!ke.isConsumed () && ke.getKeyCode () == KeyEvent.VK_ENTER) + { + String selectedItem = ((List) awtComponent).getSelectedItem (); + + // Enter only generates an Action event if something is + // selected. + if (selectedItem != null) + postActionEvent (selectedItem, ke.getModifiersEx ()); + } + } + + super.handleEvent (e); + } + + protected void postItemEvent (int item, int stateChange) + { + postItemEvent (new Integer (item), stateChange); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java new file mode 100644 index 000000000..0ee61df84 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMainThread.java @@ -0,0 +1,188 @@ +/* GtkMainThread.java -- Wrapper for the GTK main thread, and some utilities. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import gnu.java.awt.peer.NativeEventLoopRunningEvent; + +/** + * The Java thread representing the native GTK main loop, that is, + * GtkMainThread.mainThread, terminates when GtkToolkit.gtkMain() + * returns. That happens in response to the last window peer being + * disposed (see GtkWindowPeer.dispose). + * + * When GtkMainThread.destroyWindow is called for the last window, it + * in turn calls GtkMainThread.endMainThread, which calls gtk_quit. + * gtk_quit signals gtk_main to return, which causes GtkMainThread.run + * to return. + * + * There should only be one native GTK main loop running at any given + * time. In order to safely start and stop the GTK main loop, we use + * a running flag and corresponding runningLock. startMainThread will + * not return until the native GTK main loop has started, as confirmed + * by the native set_running_flag callback setting the running flag to + * true. Without this protection, gtk_quit could be called before the + * main loop has actually started, which causes GTK assertion + * failures. Likewise endMainThread will not return until the native + * GTK main loop has ended. + * + * post_running_flag_callback is called during gtk_main initialization + * and no window can be created before startMainThread returns. This + * ensures that calling post_running_flag_callback is the first action + * taken by the native GTK main loop. + * + * GtkMainThread.mainThread is started when the window count goes from + * zero to one. + * + * GtkMainThread keeps the AWT event queue informed of its status by + * posting NativeEventLoopRunningEvents. The AWT event queue uses + * this status to determine whether or not the AWT exit conditions + * have been met (see EventQueue.isShutdown). + */ +public class GtkMainThread extends Thread +{ + /** Count of the number of open windows */ + private static int numberOfWindows = 0; + + /** Lock for the above */ + private static Object nWindowsLock = new Object(); + + /** Indicates whether or not the GTK main loop is running. */ + private static boolean running = false; + + /** Lock for the above. */ + private static Object runningLock = new Object(); + + /** The main thread instance (singleton) */ + public static GtkMainThread mainThread; + + /** Constructs a main thread */ + private GtkMainThread() + { + super("GTK main thread"); + } + + public void run () + { + GtkToolkit.gtkMain (); + } + + private static void setRunning(boolean running) + { + synchronized (runningLock) + { + GtkMainThread.running = running; + runningLock.notifyAll(); + } + } + + private static void startMainThread() + { + synchronized (runningLock) + { + if (!running) + { + mainThread = new GtkMainThread(); + mainThread.start(); + + while (!running) + { + try + { + runningLock.wait(); + } + catch (InterruptedException e) + { + System.err.println ("GtkMainThread.startMainThread:" + + " interrupted while waiting " + + " for GTK main loop to start"); + } + } + GtkGenericPeer.q() + .postEvent(new NativeEventLoopRunningEvent(Boolean.TRUE)); + } + } + } + + private static void endMainThread() + { + synchronized (runningLock) + { + if (running) + { + GtkToolkit.gtkQuit(); + + while (running) + { + try + { + runningLock.wait(); + } + catch (InterruptedException e) + { + System.err.println ("GtkMainThread.endMainThread:" + + " interrupted while waiting " + + " for GTK main loop to stop"); + } + } + GtkGenericPeer.q() + .postEvent(new NativeEventLoopRunningEvent(Boolean.FALSE)); + } + } + } + + public static void createWindow() + { + synchronized (nWindowsLock) + { + if (numberOfWindows == 0) + startMainThread(); + numberOfWindows++; + } + } + + public static void destroyWindow() + { + synchronized (nWindowsLock) + { + numberOfWindows--; + if (numberOfWindows == 0) + endMainThread(); + } + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java new file mode 100644 index 000000000..c3427b18f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuBarPeer.java @@ -0,0 +1,113 @@ +/* GtkMenuBarPeer.java -- Implements MenuBarPeer with GTK+ + Copyright (C) 1999, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.peer.MenuBarPeer; + +public class GtkMenuBarPeer extends GtkMenuComponentPeer + implements MenuBarPeer +{ + /** Whether we already have an help menu set on this peer. */ + private boolean hasHelpMenu; + + /** + * Creates the gtk+ widget for this peer and puts it in the nsa + * table. Called from the (super class) constructor. + */ + protected native void create(); + + /** + * Adds a new GtkMenuPeer to the end of the GtkMenuBarPeer. + */ + private native void addMenu(GtkMenuPeer menu); + + /** + * Creates a new GtkMenuBarPeer associated with the given MenuBar. + */ + public GtkMenuBarPeer(MenuBar menubar) + { + super(menubar); + } + + /** + * Adds a help menu to this MenuBar. Gnome styleguides say the help + * menu is just the last item in the menubar (they are NOT right + * justified). + */ + public void addHelpMenu (Menu menu) + { + if (hasHelpMenu) + { + // Remove the (help) menu, which is after all the other items. + delMenu(((MenuBar) awtWidget).getMenuCount()); + hasHelpMenu = false; + } + + if (menu != null) + { + addMenu(menu); + hasHelpMenu = true; + } + } + + /** + * Deletes the menu at (zero-based) index from this GtkMenuBar. + */ + public native void delMenu(int index); + + /** + * Adds the GtkMenuPeer associated with the Menu to this + * GtkMenuBarPeer. Makes sure that any help menus keep the last menu + * on the bar. + */ + public void addMenu(Menu m) + { + // Make sure the help menu is the last one. + if (hasHelpMenu) + { + addHelpMenu(null); + addMenu((GtkMenuPeer) m.getPeer()); + addHelpMenu(((MenuBar) awtWidget).getHelpMenu()); + } + else + addMenu((GtkMenuPeer) m.getPeer()); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java new file mode 100644 index 000000000..78f640361 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuComponentPeer.java @@ -0,0 +1,104 @@ +/* GtkMenuComponentPeer.java -- Implements MenuComponentPeer with GTK+ + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Font; +import java.awt.MenuComponent; +import java.awt.MenuContainer; +import java.awt.peer.MenuComponentPeer; + +public abstract class GtkMenuComponentPeer extends GtkGenericPeer + implements MenuComponentPeer +{ + /** + * Creates the associated gtk+ widget and stores it in the nsa table + * for this peer. Called by the constructor. + */ + protected abstract void create (); + + /** + * Sets font based on MenuComponent font, or containing menu(bar) + * parent font. + */ + private void setFont() + { + MenuComponent mc = ((MenuComponent) awtWidget); + Font f = mc.getFont(); + + if (f == null) + { + MenuContainer parent = mc.getParent (); + // Submenus inherit the font of their containing Menu(Bar). + if (parent instanceof MenuComponent) + f = parent.getFont (); + } + + setFont(f); + } + + /** + * Will call the abstract create() that needs to be + * overridden by subclasses, to create the MenuComponent. It will + * then correctly setup the font for the component based on the + * component and/or its containing parent component. + */ + public GtkMenuComponentPeer(MenuComponent component) + { + super(component); + create(); + setFont(); + } + + /** + * Removes the awtWidget components from the native state tables. + * Subclasses should call super.dispose() if they don't + * remove these themselves. + */ + public native void dispose(); + + /** + * Sets the font for this particular MenuComponent only (not any + * containing items, if any). + */ + public void setFont(Font font) + { + if (font != null) + gtkWidgetModifyFont(font); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java new file mode 100644 index 000000000..ea523e953 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuItemPeer.java @@ -0,0 +1,116 @@ +/* GtkMenuItemPeer.java -- Implements MenuItemPeer with GTK+ + Copyright (C) 1999, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.MenuItem; +import java.awt.peer.MenuItemPeer; + +public class GtkMenuItemPeer extends GtkMenuComponentPeer + implements MenuItemPeer +{ + /** + * Creates the associated gtk+ widget and stores it in the nsa table + * for this peer. Called by the create() method with the label name + * of the associated MenuItem. Needs to be overridden my subclasses + * that want to create a different gtk+ widget. + */ + protected native void create (String label); + + /** + * Called from constructor to enable signals from an item. If a + * subclass needs different (or no) signals connected this method + * should be overridden. + */ + protected native void connectSignals (); + + /** + * Overridden to set font on menu item label. + */ + protected native void gtkWidgetModifyFont(String name, int style, int size); + + /** + * Creates the associated gtk+ widget and stores it in the nsa table + * for this peer. Called by the (super class) constructor. + * Overridden to get the label if the assiociated MenuItem and to + * call create(String). + */ + protected void create() + { + create (((MenuItem) awtWidget).getLabel()); + } + + /** + * Creates a new GtkMenuItemPeer associated with the given MenuItem. + * It will call create(), setFont(), setEnabled() and + * connectSignals() in that order. + */ + public GtkMenuItemPeer(MenuItem item) + { + super(item); + setEnabled (item.isEnabled()); + connectSignals(); + } + + /** + * Calls setEnabled(false). + */ + public void disable() + { + setEnabled(false); + } + + /** + * Calls setEnabled(true). + */ + public void enable() + { + setEnabled(true); + } + + public native void setEnabled(boolean b); + public native void setLabel(String label); + + /** + * Callback setup through connectSignals(). + */ + protected void postMenuActionEvent () + { + postActionEvent (((MenuItem)awtWidget).getActionCommand (), 0); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java new file mode 100644 index 000000000..c55347393 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMenuPeer.java @@ -0,0 +1,126 @@ +/* GtkMenuPeer.java -- Implements MenuPeer with GTK+ + Copyright (C) 1999, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Component; +import java.awt.Menu; +import java.awt.MenuContainer; +import java.awt.MenuItem; +import java.awt.MenuShortcut; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; + +public class GtkMenuPeer extends GtkMenuItemPeer + implements MenuPeer +{ + /** + * Creates the associated gtk+ widget and stores it in the nsa table + * for this peer. Called by the create() method with the label name + * of the associated MenuItem. Overridden to greate a Menu widget. + */ + protected native void create (String label); + + private native void addItem(MenuItemPeer item, int key, + boolean shiftModifier); + + /** XXX - Document this and the override in GtkPopupMenuPeer. */ + native void setupAccelGroup (GtkGenericPeer container); + + private native void addTearOff (); + + /** + * Overridden to not connect any signals. + */ + protected void connectSignals() + { + // No signals to connect. + } + + public GtkMenuPeer (Menu menu) + { + super (menu); + + if (menu.isTearOff()) + addTearOff(); + + MenuContainer parent = menu.getParent (); + if (parent instanceof Menu) + setupAccelGroup ((GtkMenuPeer)((Menu)parent).getPeer ()); + else if (parent instanceof Component) + setupAccelGroup ((GtkComponentPeer)((Component)parent).getPeer ()); + else + setupAccelGroup (null); // XXX, should we warn about unknown parent? + } + + public void addItem (MenuItem item) + { + int key = 0; + boolean shiftModifier = false; + + MenuShortcut ms = item.getShortcut (); + if (ms != null) + { + key = ms.getKey (); + shiftModifier = ms.usesShiftModifier (); + } + + addItem ((MenuItemPeer) item.getPeer (), key, shiftModifier); + } + + public void addItem (MenuItemPeer item, MenuShortcut ms) + { + int key = 0; + boolean shiftModifier = false; + + if (ms != null) + { + key = ms.getKey (); + shiftModifier = ms.usesShiftModifier (); + } + + addItem (item, key, shiftModifier); + } + + public native void delItem(int index); + + public void addSeparator() + { + // FIXME: implement + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java new file mode 100644 index 000000000..55c9146c4 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkMouseInfoPeer.java @@ -0,0 +1,65 @@ +/* GtkToolkit.java -- Implements an AWT Toolkit using GTK for peers + Copyright (C) 2006 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.gtk; + +import java.awt.Point; +import java.awt.GraphicsDevice; +import java.awt.Window; +import java.awt.peer.MouseInfoPeer; + +/** + * The MouseInfoPeer is so small, I'm including it here. + */ +public class GtkMouseInfoPeer implements MouseInfoPeer +{ + private static GdkGraphicsEnvironment gde = new GdkGraphicsEnvironment(); + + public int fillPointWithCoords(Point p) + { + int[] coords = gde.getMouseCoordinates(); + p.x = coords[1]; + p.y = coords[2]; + return coords[0]; + } + + public boolean isWindowUnderMouse(Window w) + { + return gde.isWindowUnderMouse((GtkWindowPeer) w.getPeer()); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkPanelPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkPanelPeer.java new file mode 100644 index 000000000..00b506c10 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkPanelPeer.java @@ -0,0 +1,67 @@ +/* GtkPanelPeer.java -- Implements PanelPeer with GTK + Copyright (C) 1998, 1999, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.AWTEvent; +import java.awt.Panel; +import java.awt.event.MouseEvent; +import java.awt.peer.PanelPeer; + +public class GtkPanelPeer extends GtkContainerPeer + implements PanelPeer +{ + native void create (); + + public GtkPanelPeer (Panel p) + { + super (p); + } + + public void handleEvent(AWTEvent event) + { + int id = event.getID(); + + if (id == MouseEvent.MOUSE_PRESSED) + awtComponent.requestFocusInWindow(); + + super.handleEvent(event); + } + + native void connectSignals (); +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java new file mode 100644 index 000000000..1b0ec8e63 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkPopupMenuPeer.java @@ -0,0 +1,68 @@ +/* GtkPopupMenuPeer.java -- Implements PopupMenuPeer with GTK+ + Copyright (C) 1999, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Component; +import java.awt.Event; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.peer.PopupMenuPeer; + +public class GtkPopupMenuPeer extends GtkMenuPeer + implements PopupMenuPeer +{ + public GtkPopupMenuPeer (PopupMenu menu) + { + super (menu); + } + + native void setupAccelGroup (GtkGenericPeer container); + + native void show (int x, int y, long time); + public void show (Component origin, int x, int y) + { + Point abs = origin.getLocationOnScreen (); + show (abs.x + x, abs.y + y, 0); + } + + public void show (Event e) + { + + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java new file mode 100644 index 000000000..657a27608 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollPanePeer.java @@ -0,0 +1,111 @@ +/* GtkScrollPanePeer.java -- Implements ScrollPanePeer with GTK + Copyright (C) 1998, 1999, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Adjustable; +import java.awt.Dimension; +import java.awt.ScrollPane; +import java.awt.peer.ScrollPanePeer; + +public class GtkScrollPanePeer extends GtkContainerPeer + implements ScrollPanePeer +{ + native void create (int width, int height); + + void create () + { + create (awtComponent.getWidth (), awtComponent.getHeight ()); + } + + // native void gtkScrolledWindowSetScrollPosition(int x, int y); + native void gtkScrolledWindowSetHScrollIncrement (int u); + native void gtkScrolledWindowSetVScrollIncrement (int u); + + public GtkScrollPanePeer (ScrollPane sp) + { + super (sp); + + setPolicy (sp.getScrollbarDisplayPolicy ()); + } + + native void setPolicy (int policy); + public void childResized (int width, int height) + { + int dim[] = new int[2]; + + gtkWidgetGetDimensions (dim); + + // If the child is in this range, GTK adds both scrollbars, but + // the AWT doesn't. So set the peer's scroll policy to + // GTK_POLICY_NEVER. + if ((width > dim[0] - getVScrollbarWidth () && width <= dim[0]) + && (height > dim[1] - getHScrollbarHeight () && height <= dim[1])) + setPolicy (ScrollPane.SCROLLBARS_NEVER); + else + setPolicy (((ScrollPane) awtComponent).getScrollbarDisplayPolicy ()); + } + + public native int getHScrollbarHeight(); + public native int getVScrollbarWidth(); + public native void setScrollPosition(int x, int y); + + public Dimension getPreferredSize () + { + return awtComponent.getSize(); + } + + public void setUnitIncrement (Adjustable adj, int u) + { + if (adj.getOrientation()==Adjustable.HORIZONTAL) + gtkScrolledWindowSetHScrollIncrement (u); + else + gtkScrolledWindowSetVScrollIncrement (u); + } + + public void setValue (Adjustable adj, int v) + { +// System.out.println("SPP: setVal: "+adj+":"+v); +// Point p=myScrollPane.getScrollPosition (); +// if (adj.getOrientation()==Adjustable.HORIZONTAL) +// gtkScrolledWindowSetScrollPosition (v,p.y); +// else +// gtkScrolledWindowSetScrollPosition (p.x,v); +// adj.setValue(v); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java new file mode 100644 index 000000000..d3f160c83 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkScrollbarPeer.java @@ -0,0 +1,92 @@ +/* GtkScrollbarPeer.java -- Implements ScrollbarPeer with GTK+ + Copyright (C) 1998, 1999, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Scrollbar; +import java.awt.event.AdjustmentEvent; +import java.awt.peer.ScrollbarPeer; + +public class GtkScrollbarPeer extends GtkComponentPeer + implements ScrollbarPeer +{ + void create () + { + Scrollbar sb = (Scrollbar) awtComponent; + + create (sb.getOrientation (), sb.getValue (), + sb.getMinimum (), sb.getMaximum (), + sb.getUnitIncrement (), sb.getBlockIncrement (), + sb.getVisibleAmount ()); + } + + native void create (int orientation, int value, + int min, int max, int stepIncr, int pageIncr, + int visibleAmount); + + native void connectSignals (); + + public GtkScrollbarPeer (Scrollbar s) + { + super (s); + } + + public native void setLineIncrement(int amount); + public native void setPageIncrement(int amount); + + public void setValues(int value, int visible, int min, int max) + { + Scrollbar sb = (Scrollbar) awtComponent; + if (!sb.getValueIsAdjusting()) + setBarValues(value, visible, min, max); + } + + private native void setBarValues(int value, int visible, int min, int max); + + /** + * Called from the native site when the scrollbar changed. + * Posts a "user generated" AdjustmentEvent to the queue. + */ + protected void postAdjustmentEvent (int type, int value) + { + Scrollbar bar = (Scrollbar) awtComponent; + q().postEvent(new AdjustmentEvent(bar, + AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + type, value, true)); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java new file mode 100644 index 000000000..78ed69676 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkSelection.java @@ -0,0 +1,675 @@ +/* GtkClipboard.java - Class representing gtk+ clipboard selection. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import gnu.classpath.Pointer; + +import java.awt.datatransfer.*; + +import java.io.*; +import java.net.*; +import java.util.*; + +import java.awt.Image; + +/** + * Class representing the gtk+ clipboard selection. This is used when + * another program owns the clipboard. Whenever the system clipboard + * selection changes we create a new instance to notify the program + * that the available flavors might have changed. When requested it + * (lazily) caches the targets, and (text, image, or files/uris) + * clipboard contents. + */ +public class GtkSelection implements Transferable +{ + /** + * Static lock used for requests of mimetypes and contents retrieval. + */ + static private Object requestLock = new Object(); + + /** + * Whether we belong to the Clipboard (true) or to the Primary selection. + */ + private final boolean clipboard; + + /** + * Whether a request for mimetypes, text, images, uris or byte[] is + * currently in progress. Should only be tested or set with + * requestLock held. When true no other requests should be made till + * it is false again. + */ + private boolean requestInProgress; + + /** + * Indicates a requestMimeTypes() call was made and the + * corresponding mimeTypesAvailable() callback was triggered. + */ + private boolean mimeTypesDelivered; + + /** + * Set and returned by getTransferDataFlavors. Only valid when + * mimeTypesDelivered is true. + */ + private DataFlavor[] dataFlavors; + + /** + * Indicates a requestText() call was made and the corresponding + * textAvailable() callback was triggered. + */ + private boolean textDelivered; + + /** + * Set as response to a requestText() call and possibly returned by + * getTransferData() for text targets. Only valid when textDelivered + * is true. + */ + private String text; + + /** + * Indicates a requestImage() call was made and the corresponding + * imageAvailable() callback was triggered. + */ + private boolean imageDelivered; + + /** + * Set as response to a requestImage() call and possibly returned by + * getTransferData() for image targets. Only valid when + * imageDelivered is true and image is null. + */ + private Pointer imagePointer; + + /** + * Cached image value. Only valid when imageDelivered is + * true. Created from imagePointer. + */ + private Image image; + + /** + * Indicates a requestUris() call was made and the corresponding + * urisAvailable() callback was triggered. + */ + private boolean urisDelivered; + + /** + * Set as response to a requestURIs() call. Only valid when + * urisDelivered is true + */ + private List uris; + + /** + * Indicates a requestBytes(String) call was made and the + * corresponding bytesAvailable() callback was triggered. + */ + private boolean bytesDelivered; + + /** + * Set as response to a requestBytes(String) call. Only valid when + * bytesDelivered is true. + */ + private byte[] bytes; + + /** + * Should only be created by the GtkClipboard class. The clipboard + * should be either GtkClipboard.clipboard or + * GtkClipboard.selection. + */ + GtkSelection(GtkClipboard clipboard) + { + this.clipboard = (clipboard == GtkClipboard.clipboard); + } + + /** + * Gets an array of mime-type strings from the gtk+ clipboard and + * transforms them into an array of DataFlavors. + */ + public DataFlavor[] getTransferDataFlavors() + { + DataFlavor[] result; + synchronized (requestLock) + { + // Did we request already and cache the result? + if (mimeTypesDelivered) + result = (DataFlavor[]) dataFlavors.clone(); + else + { + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // If nobody else beat us and cached the result we try + // ourselves to get it. + if (! mimeTypesDelivered) + { + requestInProgress = true; + requestMimeTypes(clipboard); + while (! mimeTypesDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + requestInProgress = false; + } + result = dataFlavors; + if (! GtkClipboard.canCache) + { + dataFlavors = null; + mimeTypesDelivered = false; + } + requestLock.notifyAll(); + } + } + return result; + } + + /** + * Callback that sets the available DataFlavors[]. Note that this + * should not call any code that could need the main gdk lock. + */ + private void mimeTypesAvailable(String[] mimeTypes) + { + synchronized (requestLock) + { + if (mimeTypes == null) + dataFlavors = new DataFlavor[0]; + else + { + // Most likely the mimeTypes include text in which case we add an + // extra element. + ArrayList flavorsList = + new ArrayList(mimeTypes.length + 1); + + for (int i = 0; i < mimeTypes.length; i++) + { + try + { + if (mimeTypes[i] == GtkClipboard.stringMimeType) + { + // XXX - Fix DataFlavor.getTextPlainUnicodeFlavor() + // and also add it to the list. + flavorsList.add(DataFlavor.stringFlavor); + flavorsList.add(DataFlavor.plainTextFlavor); + } + else if (mimeTypes[i] == GtkClipboard.imageMimeType) + flavorsList.add(DataFlavor.imageFlavor); + else if (mimeTypes[i] == GtkClipboard.filesMimeType) + flavorsList.add(DataFlavor.javaFileListFlavor); + else + { + // We check the target to prevent duplicates + // of the "magic" targets above. + DataFlavor target = new DataFlavor(mimeTypes[i]); + if (! flavorsList.contains(target)) + flavorsList.add(target); + } + } + catch (ClassNotFoundException cnfe) + { + cnfe.printStackTrace(); + } + catch (NullPointerException npe) + { + npe.printStackTrace(); + } + } + + dataFlavors = new DataFlavor[flavorsList.size()]; + flavorsList.toArray(dataFlavors); + } + + mimeTypesDelivered = true; + requestLock.notifyAll(); + } + } + + /** + * Gets the available data flavors for this selection and checks + * that at least one of them is equal to the given DataFlavor. + */ + public boolean isDataFlavorSupported(DataFlavor flavor) + { + DataFlavor[] dfs = getTransferDataFlavors(); + for (int i = 0; i < dfs.length; i++) + if (flavor.equals(dfs[i])) + return true; + + return false; + } + + /** + * Helper method that tests whether we already have the text for the + * current gtk+ selection on the clipboard and if not requests it + * and waits till it is available. + */ + private String getText() + { + String result; + synchronized (requestLock) + { + // Did we request already and cache the result? + if (textDelivered) + result = text; + else + { + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // If nobody else beat us we try ourselves to get and + // caching the result. + if (! textDelivered) + { + requestInProgress = true; + requestText(clipboard); + while (! textDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + requestInProgress = false; + } + result = text; + if (! GtkClipboard.canCache) + { + text = null; + textDelivered = false; + } + requestLock.notifyAll(); + } + } + return result; + } + + /** + * Callback that sets the available text on the clipboard. Note that + * this should not call any code that could need the main gdk lock. + */ + private void textAvailable(String text) + { + synchronized (requestLock) + { + this.text = text; + textDelivered = true; + requestLock.notifyAll(); + } + } + + /** + * Helper method that tests whether we already have an image for the + * current gtk+ selection on the clipboard and if not requests it + * and waits till it is available. + */ + private Image getImage() + { + Image result; + synchronized (requestLock) + { + // Did we request already and cache the result? + if (imageDelivered) + result = image; + else + { + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // If nobody else beat us we try ourselves to get and + // caching the result. + if (! imageDelivered) + { + requestInProgress = true; + requestImage(clipboard); + while (! imageDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + requestInProgress = false; + } + + if (imagePointer != null) + image = new GtkImage(imagePointer); + + imagePointer = null; + result = image; + if (! GtkClipboard.canCache) + { + image = null; + imageDelivered = false; + } + requestLock.notifyAll(); + } + } + return result; + } + + /** + * Callback that sets the available image on the clipboard. Note + * that this should not call any code that could need the main gdk + * lock. Note that we get a Pointer to a GdkPixbuf which we cannot + * turn into a real GtkImage at this point. That will be done on the + * "user thread" in getImage(). + */ + private void imageAvailable(Pointer pointer) + { + synchronized (requestLock) + { + this.imagePointer = pointer; + imageDelivered = true; + requestLock.notifyAll(); + } + } + + /** + * Helper method that test whether we already have a list of + * URIs/Files and if not requests them and waits till they are + * available. + */ + private List getURIs() + { + List result; + synchronized (requestLock) + { + // Did we request already and cache the result? + if (urisDelivered) + result = uris; + else + { + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // If nobody else beat us we try ourselves to get and + // caching the result. + if (! urisDelivered) + { + requestInProgress = true; + requestURIs(clipboard); + while (! urisDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + requestInProgress = false; + } + result = uris; + if (! GtkClipboard.canCache) + { + uris = null; + urisDelivered = false; + } + requestLock.notifyAll(); + } + } + return result; + } + + /** + * Callback that sets the available File list. Note that this should + * not call any code that could need the main gdk lock. + */ + private void urisAvailable(String[] uris) + { + synchronized (requestLock) + { + if (uris != null && uris.length != 0) + { + ArrayList list = new ArrayList(uris.length); + for (int i = 0; i < uris.length; i++) + { + try + { + URI uri = new URI(uris[i]); + if (uri.getScheme().equals("file")) + list.add(new File(uri)); + } + catch (URISyntaxException use) + { + } + } + this.uris = list; + } + + urisDelivered = true; + requestLock.notifyAll(); + } + } + + /** + * Helper method that requests a byte[] for the given target + * mime-type flavor and waits till it is available. Note that unlike + * the other get methods this one doesn't cache the result since + * there are possibly many targets. + */ + private byte[] getBytes(String target) + { + byte[] result; + synchronized (requestLock) + { + // Wait till there are no pending requests. + while (requestInProgress) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + + // Request bytes and wait till they are available. + requestInProgress = true; + requestBytes(clipboard, target); + while (! bytesDelivered) + { + try + { + requestLock.wait(); + } + catch (InterruptedException ie) + { + // ignored + } + } + result = bytes; + bytes = null; + bytesDelivered = false; + requestInProgress = false; + + requestLock.notifyAll(); + } + return result; + } + + /** + * Callback that sets the available byte array on the + * clipboard. Note that this should not call any code that could + * need the main gdk lock. + */ + private void bytesAvailable(byte[] bytes) + { + synchronized (requestLock) + { + this.bytes = bytes; + bytesDelivered = true; + requestLock.notifyAll(); + } + } + + public Object getTransferData(DataFlavor flavor) + throws UnsupportedFlavorException + { + // Note the fall throughs for the "magic targets" if they fail we + // try one more time through getBytes(). + if (flavor.equals(DataFlavor.stringFlavor)) + { + String text = getText(); + if (text != null) + return text; + } + + if (flavor.equals(DataFlavor.plainTextFlavor)) + { + String text = getText(); + if (text != null) + return new StringBufferInputStream(text); + } + + if (flavor.equals(DataFlavor.imageFlavor)) + { + Image image = getImage(); + if (image != null) + return image; + } + + if (flavor.equals(DataFlavor.javaFileListFlavor)) + { + List uris = getURIs(); + if (uris != null) + return uris; + } + + byte[] bytes = getBytes(flavor.getMimeType()); + if (bytes == null) + throw new UnsupportedFlavorException(flavor); + + if (flavor.isMimeTypeSerializedObject()) + { + try + { + ByteArrayInputStream bais = new ByteArrayInputStream(bytes); + ObjectInputStream ois = new ObjectInputStream(bais); + return ois.readObject(); + } + catch (IOException ioe) + { + ioe.printStackTrace(); + } + catch (ClassNotFoundException cnfe) + { + cnfe.printStackTrace(); + } + } + + if (flavor.isRepresentationClassInputStream()) + return new ByteArrayInputStream(bytes); + + // XXX, need some more conversions? + + throw new UnsupportedFlavorException(flavor); + } + + /* + * Requests text, Image or an byte[] for a particular target from the + * other application. These methods return immediately. When the + * content is available the contentLock will be notified through + * textAvailable, imageAvailable, urisAvailable or bytesAvailable and the + * appropriate field is set. + * The clipboard argument is true if we want the Clipboard, and false + * if we want the (primary) selection. + */ + private native void requestText(boolean clipboard); + private native void requestImage(boolean clipboard); + private native void requestURIs(boolean clipboard); + private native void requestBytes(boolean clipboard, String target); + + /* Similar to the above but for requesting the supported targets. */ + private native void requestMimeTypes(boolean clipboard); +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java new file mode 100644 index 000000000..0c7d3a860 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextAreaPeer.java @@ -0,0 +1,223 @@ +/* GtkTextAreaPeer.java -- Implements TextAreaPeer with GTK + Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Rectangle; +import java.awt.TextArea; +import java.awt.im.InputMethodRequests; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextComponentPeer; + +public class GtkTextAreaPeer extends GtkComponentPeer + implements TextComponentPeer, TextAreaPeer +{ + private static transient int DEFAULT_ROWS = 10; + private static transient int DEFAULT_COLS = 80; + + native void create (int width, int height, int scrollbarVisibility); + + /** + * Overridden to set Font for text widget inside scrolled window. + */ + protected native void gtkWidgetModifyFont(String name, int style, int size); + + native void gtkWidgetRequestFocus (); + + public native void connectSignals (); + + public native int getCaretPosition (); + public native void setCaretPosition (int pos); + public native int getSelectionStart (); + public native int getSelectionEnd (); + public native String getText (); + public native void select (int start, int end); + public native void setEditable (boolean state); + public native void setText (String text); + + public int getIndexAtPoint(int x, int y) + { + // FIXME + return 0; + } + + public Rectangle getCharacterBounds (int pos) + { + // FIXME + return null; + } + + public long filterEvents (long filter) + { + // FIXME + return filter; + } + + void create () + { + Font f = awtComponent.getFont (); + + // By default, Sun sets a TextArea's font when its peer is + // created. If f != null then the peer's font is set by + // GtkComponent.create. + if (f == null) + { + f = new Font ("Dialog", Font.PLAIN, 12); + awtComponent.setFont (f); + } + + FontMetrics fm = getFontMetrics (f); + + TextArea ta = ((TextArea) awtComponent); + int sizeRows = ta.getRows (); + int sizeCols = ta.getColumns (); + + sizeRows = sizeRows == 0 ? DEFAULT_ROWS : sizeRows; + sizeCols = sizeCols == 0 ? DEFAULT_COLS : sizeCols; + + int width = sizeCols * fm.getMaxAdvance (); + int height = sizeRows * (fm.getMaxDescent () + fm.getMaxAscent ()); + + create (width, height, ta.getScrollbarVisibility ()); + setEditable (ta.isEditable ()); + } + + public GtkTextAreaPeer (TextArea ta) + { + super (ta); + + setText (ta.getText ()); + setCaretPosition (0); + } + + public native void insert (String str, int pos); + public native void replaceRange (String str, int start, int end); + + public Dimension getMinimumSize (int rows, int cols) + { + return minimumSize (rows == 0 ? DEFAULT_ROWS : rows, + cols == 0 ? DEFAULT_COLS : cols); + } + + public Dimension getPreferredSize (int rows, int cols) + { + return preferredSize (rows == 0 ? DEFAULT_ROWS : rows, + cols == 0 ? DEFAULT_COLS : cols); + } + + native int getHScrollbarHeight (); + native int getVScrollbarWidth (); + + // Deprecated + public Dimension minimumSize (int rows, int cols) + { + TextArea ta = ((TextArea) awtComponent); + int height = 0; + int width = 0; + + if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH + || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_HORIZONTAL_ONLY) + height = getHScrollbarHeight (); + + if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH + || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_VERTICAL_ONLY) + width = getVScrollbarWidth (); + + Font f = awtComponent.getFont (); + if (f == null) + return new Dimension (width, height); + + FontMetrics fm = getFontMetrics (f); + + int sizeRows = rows == 0 ? DEFAULT_ROWS : rows; + int sizeCols = cols == 0 ? DEFAULT_COLS : cols; + + width += sizeCols * fm.getMaxAdvance (); + height += sizeRows * (fm.getMaxDescent () + fm.getMaxAscent ()); + + return new Dimension (width, height); + } + + public Dimension preferredSize (int rows, int cols) + { + TextArea ta = ((TextArea) awtComponent); + int height = 0; + int width = 0; + + if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH + || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_HORIZONTAL_ONLY) + height = getHScrollbarHeight (); + + if (ta.getScrollbarVisibility () == TextArea.SCROLLBARS_BOTH + || ta.getScrollbarVisibility () == TextArea.SCROLLBARS_VERTICAL_ONLY) + width = getVScrollbarWidth (); + + Font f = awtComponent.getFont (); + if (f == null) + return new Dimension (width, height); + + FontMetrics fm = getFontMetrics (f); + + int sizeRows = rows == 0 ? DEFAULT_ROWS : rows; + int sizeCols = cols == 0 ? DEFAULT_COLS : cols; + + width += sizeCols * fm.getMaxAdvance (); + height += sizeRows * (fm.getMaxDescent () + fm.getMaxAscent ()); + + return new Dimension (width, height); + } + + public void replaceText (String str, int start, int end) + { + replaceRange (str, start, end); + } + + public void insertText (String str, int pos) + { + insert (str, pos); + } + + public InputMethodRequests getInputMethodRequests() + { + // FIXME: implement + return null; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java new file mode 100644 index 000000000..9e62c8e79 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkTextFieldPeer.java @@ -0,0 +1,200 @@ +/* GtkTextFieldPeer.java -- Implements TextFieldPeer with GTK + Copyright (C) 1998, 1999, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.AWTEvent; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Rectangle; +import java.awt.TextField; +import java.awt.event.KeyEvent; +import java.awt.im.InputMethodRequests; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.TextComponentPeer; + +public class GtkTextFieldPeer extends GtkComponentPeer + implements TextComponentPeer, TextFieldPeer +{ + native void create (int width); + native void gtkWidgetSetBackground (int red, int green, int blue); + native void gtkWidgetSetForeground (int red, int green, int blue); + + public native void connectSignals (); + + public native int getCaretPosition (); + public native void setCaretPosition (int pos); + public native int getSelectionStart (); + public native int getSelectionEnd (); + public native String getText (); + public native void select (int start, int end); + public native void setEditable (boolean state); + public native void setText (String text); + + public int getIndexAtPoint(int x, int y) + { + // FIXME + return 0; + } + + public Rectangle getCharacterBounds (int pos) + { + // FIXME + return null; + } + + public long filterEvents (long filter) + { + // FIXME + return filter; + } + + void create () + { + Font f = awtComponent.getFont (); + + // By default, Sun sets a TextField's font when its peer is + // created. If f != null then the peer's font is set by + // GtkComponent.create. + if (f == null) + { + f = new Font ("Dialog", Font.PLAIN, 12); + awtComponent.setFont (f); + } + + FontMetrics fm = getFontMetrics (f); + + TextField tf = ((TextField) awtComponent); + int cols = tf.getColumns (); + + int text_width = cols * fm.getMaxAdvance (); + + create (text_width); + + setEditable (tf.isEditable ()); + } + + native int gtkEntryGetBorderWidth (); + + public GtkTextFieldPeer (TextField tf) + { + super (tf); + + setText (tf.getText ()); + setCaretPosition (0); + + if (tf.echoCharIsSet ()) + setEchoChar (tf.getEchoChar ()); + } + + public Dimension getMinimumSize (int cols) + { + return minimumSize (cols); + } + + public Dimension getPreferredSize (int cols) + { + return preferredSize (cols); + } + + public native void setEchoChar (char c); + + // Deprecated + public Dimension minimumSize (int cols) + { + int dim[] = new int[2]; + + gtkWidgetGetPreferredDimensions (dim); + + Font f = awtComponent.getFont (); + if (f == null) + return new Dimension (2 * gtkEntryGetBorderWidth (), dim[1]); + + FontMetrics fm = getFontMetrics (f); + + int text_width = cols * fm.getMaxAdvance (); + + int width = text_width + 2 * gtkEntryGetBorderWidth (); + + return new Dimension (width, dim[1]); + } + + public Dimension preferredSize (int cols) + { + int dim[] = new int[2]; + + gtkWidgetGetPreferredDimensions (dim); + + Font f = awtComponent.getFont (); + if (f == null) + return new Dimension (2 * gtkEntryGetBorderWidth (), dim[1]); + + FontMetrics fm = getFontMetrics (f); + + int text_width = cols * fm.getMaxAdvance (); + + int width = text_width + 2 * gtkEntryGetBorderWidth (); + + return new Dimension (width, dim[1]); + } + + public void setEchoCharacter (char c) + { + setEchoChar (c); + } + + public void handleEvent (AWTEvent e) + { + if (e.getID () == KeyEvent.KEY_PRESSED) + { + KeyEvent ke = (KeyEvent) e; + + if (!ke.isConsumed () + && ke.getKeyCode () == KeyEvent.VK_ENTER) + postActionEvent (getText (), ke.getModifiersEx ()); + } + + super.handleEvent (e); + } + public InputMethodRequests getInputMethodRequests() + { + // FIXME: implement + return null; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java new file mode 100644 index 000000000..150656511 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkToolkit.java @@ -0,0 +1,766 @@ +/* GtkToolkit.java -- Implements an AWT Toolkit using GTK for peers + Copyright (C) 1998, 1999, 2002, 2003, 2004, 2005, 2006, 2007 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import gnu.classpath.Configuration; + +import gnu.java.awt.AWTUtilities; +import gnu.java.awt.EmbeddedWindow; +import gnu.java.awt.dnd.GtkMouseDragGestureRecognizer; +import gnu.java.awt.dnd.peer.gtk.GtkDragSourceContextPeer; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.peer.EmbeddedWindowPeer; + +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.Component; +import java.awt.Cursor; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Image; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.PrintJob; +import java.awt.Rectangle; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Window; +import java.awt.datatransfer.Clipboard; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.DragGestureListener; +import java.awt.dnd.DragGestureRecognizer; +import java.awt.dnd.DragSource; +import java.awt.dnd.InvalidDnDOperationException; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.font.TextAttribute; +import java.awt.im.InputMethodHighlight; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.ButtonPeer; +import java.awt.peer.CanvasPeer; +import java.awt.peer.CheckboxMenuItemPeer; +import java.awt.peer.CheckboxPeer; +import java.awt.peer.ChoicePeer; +import java.awt.peer.DialogPeer; +import java.awt.peer.FileDialogPeer; +import java.awt.peer.FontPeer; +import java.awt.peer.FramePeer; +import java.awt.peer.LabelPeer; +import java.awt.peer.ListPeer; +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; +import java.awt.peer.MouseInfoPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.PopupMenuPeer; +import java.awt.peer.RobotPeer; +import java.awt.peer.ScrollPanePeer; +import java.awt.peer.ScrollbarPeer; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.WindowPeer; +import java.io.InputStream; +import java.net.URL; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.Properties; + +import javax.imageio.spi.IIORegistry; + +/* This class uses a deprecated method java.awt.peer.ComponentPeer.getPeer(). + This merits comment. We are basically calling Sun's bluff on this one. + We think Sun has deprecated it simply to discourage its use as it is + bad programming style. However, we need to get at a component's peer in + this class. If getPeer() ever goes away, we can implement a hash table + that will keep up with every window's peer, but for now this is faster. */ + +public class GtkToolkit extends gnu.java.awt.ClasspathToolkit +{ + static final Object GTK_LOCK; + + private static EventQueue q; + + static native void gtkInit(int portableNativeSync, Object lock); + + static native void gtkMain(); + + static native void gtkQuit(); + + /** + * Initializes field IDs that are used by native code. + */ + private static native void initIDs(); + + /** + * True when the field IDs are already initialized, false otherwise. + */ + private static boolean initializedGlobalIDs = false; + + /** + * Initializes some global fieldIDs for use in the native code. This is + * called by a couple of classes in the GTK peers to ensure that + * some necessary stuff is loaded. + */ + static synchronized void initializeGlobalIDs() + { + if (! initializedGlobalIDs) + { + initIDs(); + initializedGlobalIDs = true; + } + } + + static + { + if (true) // GCJ LOCAL + { + System.loadLibrary("gtkpeer"); + } + + /** + * Gotta do that first. + */ + initializeGlobalIDs(); + + int portableNativeSync; + String portNatSyncProp = + System.getProperty("gnu.classpath.awt.gtk.portable.native.sync"); + + if (portNatSyncProp == null) + portableNativeSync = -1; // unset + else if (Boolean.valueOf(portNatSyncProp).booleanValue()) + portableNativeSync = 1; // true + else + portableNativeSync = 0; // false + + GTK_LOCK = new String("GTK LOCK"); + gtkInit(portableNativeSync, GTK_LOCK); + } + + public GtkToolkit () + { + } + + public native void beep(); + + private native void getScreenSizeDimensions(int[] xy); + + public int checkImage (Image image, int width, int height, + ImageObserver observer) + { + int status = ImageObserver.ALLBITS + | ImageObserver.WIDTH + | ImageObserver.HEIGHT; + + if (image instanceof GtkImage) + return ((GtkImage) image).checkImage (observer); + + if (image instanceof AsyncImage) + return ((AsyncImage) image).checkImage(observer); + + if (observer != null) + observer.imageUpdate (image, status, + -1, -1, + image.getWidth (observer), + image.getHeight (observer)); + + return status; + } + + /** + * Helper to return either a Image -- the argument -- or a + * GtkImage with the errorLoading flag set if the argument is null. + */ + static Image imageOrError(Image b) + { + if (b == null) + return GtkImage.getErrorImage(); + else + return b; + } + + public Image createImage (String filename) + { + if (filename.length() == 0) + return new GtkImage (); + + Image image; + try + { + image = CairoSurface.getBufferedImage( new GtkImage( filename ) ); + } + catch (IllegalArgumentException iae) + { + image = null; + } + return imageOrError(image); + } + + public Image createImage (URL url) + { + return new AsyncImage(url); + } + + public Image createImage (ImageProducer producer) + { + if (producer == null) + return null; + + Image image; + try + { + image = CairoSurface.getBufferedImage( new GtkImage( producer ) ); + } + catch (IllegalArgumentException iae) + { + image = null; + } + return imageOrError(image); + } + + public Image createImage (byte[] imagedata, int imageoffset, + int imagelength) + { + Image image; + try + { + byte[] data = new byte[ imagelength ]; + System.arraycopy(imagedata, imageoffset, data, 0, imagelength); + image = CairoSurface.getBufferedImage( new GtkImage( data ) ); + } + catch (IllegalArgumentException iae) + { + image = null; + } + return imageOrError(image); + } + + /** + * Creates an ImageProducer from the specified URL. The image is assumed + * to be in a recognised format. + * + * @param url URL to read image data from. + */ + public ImageProducer createImageProducer(URL url) + { + return createImage( url ).getSource(); + } + + /** + * Returns the native color model (which isn't the same as the default + * ARGB color model, but doesn't have to be). + */ + public ColorModel getColorModel () + { + /* Return the GDK-native ABGR format */ + return new DirectColorModel(32, + 0x000000FF, + 0x0000FF00, + 0x00FF0000, + 0xFF000000); + } + + public String[] getFontList () + { + return (new String[] { "Dialog", + "DialogInput", + "Monospaced", + "Serif", + "SansSerif" }); + } + + static class LRUCache extends LinkedHashMap + { + int max_entries; + public LRUCache(int max) + { + super(max, 0.75f, true); + max_entries = max; + } + protected boolean removeEldestEntry(Map.Entry eldest) + { + return size() > max_entries; + } + } + + private LRUCache fontCache = + new LRUCache(50); + private LRUCache imageCache = new LRUCache(50); + + public FontMetrics getFontMetrics (Font font) + { + return ((GdkFontPeer) font.getPeer()).getFontMetrics(font); + } + + public Image getImage (String filename) + { + if (imageCache.containsKey(filename)) + return imageCache.get(filename); + else + { + Image im = createImage(filename); + imageCache.put(filename, im); + return im; + } + } + + public Image getImage (URL url) + { + if (imageCache.containsKey(url)) + return imageCache.get(url); + else + { + Image im = createImage(url); + imageCache.put(url, im); + return im; + } + } + + public PrintJob getPrintJob (Frame frame, String jobtitle, Properties props) + { + SecurityManager sm; + sm = System.getSecurityManager(); + if (sm != null) + sm.checkPrintJobAccess(); + + return null; + } + + public native int getScreenResolution(); + + public Dimension getScreenSize () + { + int dim[] = new int[2]; + getScreenSizeDimensions(dim); + return new Dimension(dim[0], dim[1]); + } + + public Clipboard getSystemClipboard() + { + SecurityManager secman = System.getSecurityManager(); + if (secman != null) + secman.checkSystemClipboardAccess(); + + return GtkClipboard.getClipboardInstance(); + } + + public Clipboard getSystemSelection() + { + SecurityManager secman = System.getSecurityManager(); + if (secman != null) + secman.checkSystemClipboardAccess(); + + return GtkClipboard.getSelectionInstance(); + } + + /** + * Prepares a GtkImage. For every other kind of Image it just + * assumes the image is already prepared for rendering. + */ + public boolean prepareImage (Image image, int width, int height, + ImageObserver observer) + { + /* GtkImages are always prepared, as long as they're loaded. */ + if (image instanceof GtkImage) + return ((((GtkImage)image).checkImage (observer) + & ImageObserver.ALLBITS) != 0); + + if (image instanceof AsyncImage) + { + AsyncImage aImg = (AsyncImage) image; + aImg.addObserver(observer); + return aImg.realImage != null; + } + + /* Assume anything else is too */ + return true; + } + + public native void sync(); + + protected void setComponentState (Component c, GtkComponentPeer cp) + { + /* Make the Component reflect Peer defaults */ + if (c.getForeground () == null) + c.setForeground (cp.getForeground ()); + if (c.getBackground () == null) + c.setBackground (cp.getBackground ()); + // if (c.getFont () == null) + // c.setFont (cp.getFont ()); + + /* Make the Peer reflect the state of the Component */ + if (! (c instanceof Window)) + { + cp.setCursor (c.getCursor ()); + + Rectangle bounds = c.getBounds (); + cp.setBounds (bounds.x, bounds.y, bounds.width, bounds.height); + cp.setVisible (c.isVisible ()); + } + } + + protected ButtonPeer createButton (Button b) + { + checkHeadless(); + return new GtkButtonPeer (b); + } + + protected CanvasPeer createCanvas (Canvas c) + { + checkHeadless(); + return new GtkCanvasPeer (c); + } + + protected CheckboxPeer createCheckbox (Checkbox cb) + { + checkHeadless(); + return new GtkCheckboxPeer (cb); + } + + protected CheckboxMenuItemPeer createCheckboxMenuItem (CheckboxMenuItem cmi) + { + checkHeadless(); + return new GtkCheckboxMenuItemPeer (cmi); + } + + protected ChoicePeer createChoice (Choice c) + { + checkHeadless(); + return new GtkChoicePeer (c); + } + + protected DialogPeer createDialog (Dialog d) + { + checkHeadless(); + GtkMainThread.createWindow(); + return new GtkDialogPeer (d); + } + + protected FileDialogPeer createFileDialog (FileDialog fd) + { + checkHeadless(); + return new GtkFileDialogPeer (fd); + } + + protected FramePeer createFrame (Frame f) + { + checkHeadless(); + GtkMainThread.createWindow(); + return new GtkFramePeer (f); + } + + protected LabelPeer createLabel (Label label) + { + checkHeadless(); + return new GtkLabelPeer (label); + } + + protected ListPeer createList (List list) + { + checkHeadless(); + return new GtkListPeer (list); + } + + protected MenuPeer createMenu (Menu m) + { + checkHeadless(); + return new GtkMenuPeer (m); + } + + protected MenuBarPeer createMenuBar (MenuBar mb) + { + checkHeadless(); + return new GtkMenuBarPeer (mb); + } + + protected MenuItemPeer createMenuItem (MenuItem mi) + { + checkHeadless(); + return new GtkMenuItemPeer (mi); + } + + protected PanelPeer createPanel (Panel p) + { + checkHeadless(); + return new GtkPanelPeer (p); + } + + protected PopupMenuPeer createPopupMenu (PopupMenu target) + { + checkHeadless(); + return new GtkPopupMenuPeer (target); + } + + protected ScrollPanePeer createScrollPane (ScrollPane sp) + { + checkHeadless(); + return new GtkScrollPanePeer (sp); + } + + protected ScrollbarPeer createScrollbar (Scrollbar sb) + { + checkHeadless(); + return new GtkScrollbarPeer (sb); + } + + protected TextAreaPeer createTextArea (TextArea ta) + { + checkHeadless(); + return new GtkTextAreaPeer (ta); + } + + protected TextFieldPeer createTextField (TextField tf) + { + checkHeadless(); + return new GtkTextFieldPeer (tf); + } + + protected WindowPeer createWindow (Window w) + { + checkHeadless(); + GtkMainThread.createWindow(); + return new GtkWindowPeer (w); + } + + public EmbeddedWindowPeer createEmbeddedWindow (EmbeddedWindow w) + { + checkHeadless(); + GtkMainThread.createWindow(); + return new GtkEmbeddedWindowPeer (w); + } + + /** + * @deprecated part of the older "logical font" system in earlier AWT + * implementations. Our newer Font class uses getClasspathFontPeer. + */ + protected FontPeer getFontPeer (String name, int style) { + // All fonts get a default size of 12 if size is not specified. + return getFontPeer(name, style, 12); + } + + /** + * Private method that allows size to be set at initialization time. + */ + private FontPeer getFontPeer (String name, int style, int size) + { + Map attrs = new HashMap(); + ClasspathFontPeer.copyStyleToAttrs (style, attrs); + ClasspathFontPeer.copySizeToAttrs (size, attrs); + return getClasspathFontPeer (name, attrs); + } + + /** + * Newer method to produce a peer for a Font object, even though Sun's + * design claims Font should now be peerless, we do not agree with this + * model, hence "ClasspathFontPeer". + */ + + public ClasspathFontPeer getClasspathFontPeer (String name, + Map attrs) + { + Map keyMap = new HashMap(attrs); + // We don't know what kind of "name" the user requested (logical, face, + // family), and we don't actually *need* to know here. The worst case + // involves failure to consolidate fonts with the same backend in our + // cache. This is harmless. + keyMap.put ("GtkToolkit.RequestedFontName", name); + if (fontCache.containsKey (keyMap)) + return fontCache.get (keyMap); + else + { + ClasspathFontPeer newPeer = new GdkFontPeer (name, attrs); + fontCache.put (keyMap, newPeer); + return newPeer; + } + } + + protected EventQueue getSystemEventQueueImpl() + { + synchronized (GtkToolkit.class) + { + if (q == null) + { + q = new EventQueue(); + } + } + return q; + } + + public Cursor createCustomCursor(Image image, Point hotspot, String name) + { + return new GtkCursor(image, hotspot, name); + } + + protected native void loadSystemColors (int[] systemColors); + + public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e) + { + if (GraphicsEnvironment.isHeadless()) + throw new InvalidDnDOperationException(); + return new GtkDragSourceContextPeer(e); + } + + public T + createDragGestureRecognizer(Class recognizer, DragSource ds, + Component comp, int actions, + DragGestureListener l) + { + if (recognizer.getName().equals("java.awt.dnd.MouseDragGestureRecognizer") + && ! GraphicsEnvironment.isHeadless()) + { + GtkMouseDragGestureRecognizer gestureRecognizer + = new GtkMouseDragGestureRecognizer(ds, comp, actions, l); + gestureRecognizer.registerListeners(); + return recognizer.cast(gestureRecognizer); + } + else + { + return null; + } + } + + public Map mapInputMethodHighlight(InputMethodHighlight highlight) + { + throw new Error("not implemented"); + } + + public Rectangle getBounds() + { + int[] dims = new int[2]; + getScreenSizeDimensions(dims); + return new Rectangle(0, 0, dims[0], dims[1]); + } + + // ClasspathToolkit methods + + public GraphicsEnvironment getLocalGraphicsEnvironment() + { + return new GdkGraphicsEnvironment(); + } + + public Font createFont(int format, InputStream stream) + { + throw new UnsupportedOperationException(); + } + + public RobotPeer createRobot (GraphicsDevice screen) throws AWTException + { + return new GdkRobotPeer (screen); + } + + public boolean getLockingKeyState(int keyCode) + { + int state = getLockState(keyCode); + + if (state != -1) + return state == 1; + + if (AWTUtilities.isValidKey(keyCode)) + throw new UnsupportedOperationException + ("cannot get locking state of key code " + keyCode); + + throw new IllegalArgumentException("invalid key code " + keyCode); + } + + protected native int getLockState(int keyCode); + + public void registerImageIOSpis(IIORegistry reg) + { + GdkPixbufDecoder.registerSpis(reg); + } + + protected MouseInfoPeer getMouseInfoPeer() + { + return new GtkMouseInfoPeer(); + } + + public boolean isFrameStateSupported(int state) + { + // GTK supports ICONFIED, NORMAL and MAXIMIZE_BOTH, but + // not (yet?) MAXIMIZE_VERT and MAXIMIZE_HORIZ. + return state == Frame.NORMAL || state == Frame.ICONIFIED + || state == Frame.MAXIMIZED_BOTH; + } + + private void checkHeadless() + { + if (GraphicsEnvironment.isHeadless()) + throw new HeadlessException(); + } + + public native int getMouseNumberOfButtons(); + + @Override + public boolean isModalExclusionTypeSupported + (Dialog.ModalExclusionType modalExclusionType) + { + return false; + } + + @Override + public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) + { + return false; + } + +} // class GtkToolkit diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java new file mode 100644 index 000000000..663839f23 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkVolatileImage.java @@ -0,0 +1,207 @@ +/* GtkVolatileImage.java -- wraps an X pixmap + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.gtk; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.ImageCapabilities; +import java.awt.Point; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.SinglePixelPackedSampleModel; +import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; + +public class GtkVolatileImage extends VolatileImage +{ + int width, height; + private ImageCapabilities caps; + + final GtkComponentPeer component; + + static ColorModel gdkColorModel = new DirectColorModel(32, + 0x000000FF, + 0x0000FF00, + 0x00FF0000, + 0xFF000000); + + /** + * Don't touch, accessed from native code. + */ + long nativePointer; + + native long init(GtkComponentPeer component, int width, int height); + + native void destroy(long pointer); + + native int[] nativeGetPixels(long pointer); + + /** + * Gets the pixels in the current image from GDK. + * + * Note that pixels are in 32-bit RGBA, non-premultiplied, which is different + * from Cairo's premultiplied ARGB, which is different from Java's standard + * non-premultiplied ARGB. Caution is advised when using this method, to + * ensure that the data format remains consistent with what you expect. + * + * @return the current pixels, as reported by GDK. + */ + public int[] getPixels() + { + return nativeGetPixels(nativePointer); + } + + native void nativeCopyArea(long pointer, int x, int y, int w, int h, int dx, + int dy ); + public void copyArea(int x, int y, int w, int h, int dx, int dy) + { + nativeCopyArea(nativePointer, x, y, w, h, dx, dy); + } + + native void nativeDrawVolatile(long pointer, long srcPtr, int x, int y, + int w, int h ); + public void drawVolatile(long srcPtr, int x, int y, int w, int h ) + { + nativeDrawVolatile(nativePointer, srcPtr, x, y, w, h); + } + + public GtkVolatileImage(GtkComponentPeer component, + int width, int height, ImageCapabilities caps) + { + this.width = width; + this.height = height; + this.caps = caps; + this.component = component; + nativePointer = init( component, width, height ); + } + + public GtkVolatileImage(int width, int height, ImageCapabilities caps) + { + this(null, width, height, caps); + } + + public GtkVolatileImage(int width, int height) + { + this(null, width, height, null); + } + + public void finalize() + { + dispose(); + } + + public void dispose() + { + destroy(nativePointer); + } + + public BufferedImage getSnapshot() + { + WritableRaster raster = Raster.createWritableRaster(createGdkSampleModel(width, height), + new Point(0, 0)); + raster.setDataElements(0, 0, getPixels()); + return new BufferedImage(gdkColorModel, raster, + gdkColorModel.isAlphaPremultiplied(), null); + } + + public Graphics getGraphics() + { + return createGraphics(); + } + + public Graphics2D createGraphics() + { + return new VolatileImageGraphics( this ); + } + + public int validate(GraphicsConfiguration gc) + { + return VolatileImage.IMAGE_OK; + } + + public boolean contentsLost() + { + return false; + } + + public ImageCapabilities getCapabilities() + { + return caps; + } + + public int getWidth() + { + return width; + } + + public int getHeight() + { + return height; + } + + public int getWidth(java.awt.image.ImageObserver observer) + { + return width; + } + + public int getHeight(java.awt.image.ImageObserver observer) + { + return height; + } + + public Object getProperty(String name, ImageObserver observer) + { + return null; + } + + /** + * Creates a SampleModel that matches GDK's native format + */ + protected static SampleModel createGdkSampleModel(int w, int h) + { + return new SinglePixelPackedSampleModel(DataBuffer.TYPE_INT, w, h, + new int[]{0x000000FF, 0x0000FF00, + 0x00FF0000, 0xFF000000}); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java new file mode 100644 index 000000000..c8e1bceb7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/GtkWindowPeer.java @@ -0,0 +1,437 @@ +/* GtkWindowPeer.java -- Implements WindowPeer with GTK + Copyright (C) 1998, 1999, 2002, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import gnu.java.awt.ComponentReshapeEvent; + +import java.awt.Component; +import java.awt.Font; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.KeyboardFocusManager; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Window; +import java.awt.event.ComponentEvent; +import java.awt.event.FocusEvent; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; +import java.awt.peer.WindowPeer; + +public class GtkWindowPeer extends GtkContainerPeer + implements WindowPeer +{ + protected static final int GDK_WINDOW_TYPE_HINT_NORMAL = 0; + protected static final int GDK_WINDOW_TYPE_HINT_DIALOG = 1; + protected static final int GDK_WINDOW_TYPE_HINT_MENU = 2; + protected static final int GDK_WINDOW_TYPE_HINT_TOOLBAR = 3; + protected static final int GDK_WINDOW_TYPE_HINT_SPLASHSCREEN = 4; + protected static final int GDK_WINDOW_TYPE_HINT_UTILITY = 5; + protected static final int GDK_WINDOW_TYPE_HINT_DOCK = 6; + protected static final int GDK_WINDOW_TYPE_HINT_DESKTOP = 7; + + protected int windowState = Frame.NORMAL; + + // Cached awt window component location, width and height. + private int x, y, width, height; + + native void gtkWindowSetTitle (String title); + native void gtkWindowSetResizable (boolean resizable); + native void gtkWindowSetModal (boolean modal); + native void gtkWindowSetAlwaysOnTop ( boolean alwaysOnTop ); + native boolean gtkWindowHasFocus(); + native void realize (); + + public void dispose() + { + super.dispose(); + GtkMainThread.destroyWindow(); + } + + /** Returns the cached width of the AWT window component. */ + int getX () + { + return x; + } + + /** Returns the cached width of the AWT window component. */ + int getY () + { + return y; + } + + /** Returns the cached width of the AWT window component. */ + int getWidth () + { + return width; + } + + /** Returns the cached height of the AWT window component. */ + int getHeight () + { + return height; + } + + native void create (int type, boolean decorated, GtkWindowPeer parent); + + void create (int type, boolean decorated) + { + Window window = (Window) awtComponent; + GtkWindowPeer parent_peer = null; + Component parent = awtComponent.getParent(); + x = awtComponent.getX(); + y = awtComponent.getY(); + height = awtComponent.getHeight(); + width = awtComponent.getWidth(); + + if (!window.isFocusableWindow()) + type = GDK_WINDOW_TYPE_HINT_MENU; + + if (parent != null) + parent_peer = (GtkWindowPeer) awtComponent.getParent().getPeer(); + + create (type, decorated, parent_peer); + } + + void create () + { + // Create a normal undecorated window. + create (GDK_WINDOW_TYPE_HINT_NORMAL, false); + } + + void setParent () + { + setVisible (awtComponent.isVisible ()); + setEnabled (awtComponent.isEnabled ()); + } + + void setVisibleAndEnabled () + { + } + + public native void setVisibleNative (boolean b); + public native void setVisibleNativeUnlocked (boolean b); + + native void connectSignals (); + + public GtkWindowPeer (Window window) + { + super (window); + // Set reasonable font for the window. + window.setFont(new Font("Dialog", Font.PLAIN, 12)); + } + + public native void toBack(); + public native void toFront(); + + native void nativeSetBounds (int x, int y, int width, int height); + native void nativeSetBoundsUnlocked (int x, int y, int width, int height); + native void nativeSetLocation (int x, int y); + native void nativeSetLocationUnlocked (int x, int y); + + // Called from show. + protected void setLocation (int x, int y) + { + nativeSetLocation (x, y); + } + + public void setBounds (int x, int y, int width, int height) + { + if (x != getX() || y != getY() || width != getWidth() + || height != getHeight()) + { + this.x = x; + this.y = y; + this.width = width; + this.height = height; + + nativeSetBounds (x, y, + width - insets.left - insets.right, + height - insets.top - insets.bottom); + } + } + + public void setTitle (String title) + { + gtkWindowSetTitle (title); + } + + // Called from setResizable + protected native void setSize (int width, int height); + + /** + * Needed by both GtkFramePeer and GtkDialogPeer subclasses, so + * implemented here. But never actually called on a GtkWindowPeer + * itself. + */ + public void setResizable (boolean resizable) + { + // Call setSize; otherwise when resizable is changed from true to + // false the window will shrink to the dimensions it had before it + // was resizable. + x = awtComponent.getX(); + y = awtComponent.getY(); + width = awtComponent.getWidth(); + height = awtComponent.getHeight(); + setSize (width - insets.left - insets.right, + height - insets.top - insets.bottom); + gtkWindowSetResizable (resizable); + } + + protected void postInsetsChangedEvent (int top, int left, + int bottom, int right) + { + insets.top = top; + insets.left = left; + insets.bottom = bottom; + insets.right = right; + } + + // called back by native side: window_configure_cb + // only called from GTK thread + protected void postConfigureEvent (int x, int y, int width, int height) + { + int frame_x = x - insets.left; + int frame_y = y - insets.top; + int frame_width = width + insets.left + insets.right; + int frame_height = height + insets.top + insets.bottom; + + // Update the component's knowledge about the size. + // Important: Please look at the big comment in ComponentReshapeEvent + // to learn why we did it this way. If you change this code, make + // sure that the peer->AWT bounds update still works. + // (for instance: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29448 ) + + // We do this befor we post the ComponentEvent, because (in Window) + // we invalidate() / revalidate() when a ComponentEvent is seen, + // and the AWT must already know about the new size then. + if (frame_x != this.x || frame_y != this.y || frame_width != this.width + || frame_height != this.height) + { + ComponentReshapeEvent ev = new ComponentReshapeEvent(awtComponent, + frame_x, + frame_y, + frame_width, + frame_height); + awtComponent.dispatchEvent(ev); + } + + if (frame_width != getWidth() || frame_height != getHeight()) + { + this.width = frame_width; + this.height = frame_height; + q().postEvent(new ComponentEvent(awtComponent, + ComponentEvent.COMPONENT_RESIZED)); + } + + if (frame_x != getX() || frame_y != getY()) + { + this.x = frame_x; + this.y = frame_y; + q().postEvent(new ComponentEvent(awtComponent, + ComponentEvent.COMPONENT_MOVED)); + } + + } + + public void show () + { + x = awtComponent.getX(); + y = awtComponent.getY(); + width = awtComponent.getWidth(); + height = awtComponent.getHeight(); + setLocation(x, y); + setVisible (true); + } + + void postWindowEvent (int id, Window opposite, int newState) + { + if (id == WindowEvent.WINDOW_STATE_CHANGED) + { + if (windowState != newState) + { + // Post old styleWindowEvent with WINDOW_ICONIFIED or + // WINDOW_DEICONIFIED if appropriate. + if ((windowState & Frame.ICONIFIED) != 0 + && (newState & Frame.ICONIFIED) == 0) + q().postEvent(new WindowEvent((Window) awtComponent, + WindowEvent.WINDOW_DEICONIFIED, + opposite, 0, 0)); + else if ((windowState & Frame.ICONIFIED) == 0 + && (newState & Frame.ICONIFIED) != 0) + q().postEvent(new WindowEvent((Window) awtComponent, + WindowEvent.WINDOW_ICONIFIED, + opposite, 0, 0)); + // Post new-style WindowStateEvent. + q().postEvent (new WindowEvent ((Window) awtComponent, id, + opposite, windowState, newState)); + windowState = newState; + } + } + else + q().postEvent (new WindowEvent ((Window) awtComponent, id, opposite)); + } + + /** + * Update the always-on-top status of the native window. + */ + public void updateAlwaysOnTop() + { + gtkWindowSetAlwaysOnTop( ((Window)awtComponent).isAlwaysOnTop() ); + } + + protected void postExposeEvent (int x, int y, int width, int height) + { + // Translate GTK co-ordinates, which do not include a window + // frame's insets, to AWT co-ordinates, which do include a window + // frame's insets. GtkWindowPeer should always have all-zero + // insets but GtkFramePeer and GtkDialogPeer insets will be + // non-zero. + q().postEvent (new PaintEvent (awtComponent, PaintEvent.PAINT, + new Rectangle (x + insets.left, + y + insets.top, + width, height))); + } + + public boolean requestWindowFocus() + { + // TODO Auto-generated method stub + return false; + } + + public boolean requestFocus (Component request, boolean temporary, + boolean allowWindowFocus, long time) + { + assert request == awtComponent || isLightweightDescendant(request); + boolean retval = false; + if (gtkWindowHasFocus()) + { + KeyboardFocusManager kfm = + KeyboardFocusManager.getCurrentKeyboardFocusManager(); + Component currentFocus = kfm.getFocusOwner(); + if (currentFocus == request) + // Nothing to do in this trivial case. + retval = true; + else + { + // Requested component is a lightweight descendant of this one + // or the actual heavyweight. + // Since this (native) component is already focused, we simply + // change the actual focus and be done. + postFocusEvent(FocusEvent.FOCUS_GAINED, temporary); + retval = true; + } + } + else + { + if (allowWindowFocus) + { + retval = requestWindowFocus(); + } + } + return retval; + } + + public Graphics getGraphics () + { + Graphics g = super.getGraphics (); + // Translate AWT co-ordinates, which include a window frame's + // insets, to GTK co-ordinates, which do not include a window + // frame's insets. GtkWindowPeer should always have all-zero + // insets but GtkFramePeer and GtkDialogPeer insets will be + // non-zero. + g.translate (-insets.left, -insets.top); + return g; + } + + protected void postMouseEvent(int id, long when, int mods, int x, int y, + int clickCount, boolean popupTrigger) + { + // Translate AWT co-ordinates, which include a window frame's + // insets, to GTK co-ordinates, which do not include a window + // frame's insets. GtkWindowPeer should always have all-zero + // insets but GtkFramePeer and GtkDialogPeer insets will be + // non-zero. + super.postMouseEvent (id, when, mods, + x + insets.left, y + insets.top, + clickCount, popupTrigger); + } + + public Point getLocationOnScreen() + { + int point[] = new int[2]; + if (Thread.currentThread() == GtkMainThread.mainThread) + gtkWindowGetLocationOnScreenUnlocked(point); + else + gtkWindowGetLocationOnScreen(point); + return new Point(point[0], point[1]); + } + + // We override this to keep it in sync with our internal + // representation. + public Rectangle getBounds() + { + return new Rectangle(x, y, width, height); + } + + public void updateIconImages() + { + // TODO: Implement properly. + } + + public void updateMinimumSize() + { + // TODO: Implement properly. + } + + public void setModalBlocked(java.awt.Dialog d, boolean b) + { + // TODO: Implement properly. + } + + public void updateFocusableWindowState() + { + // TODO: Implement properly. + } + + public void setAlwaysOnTop(boolean b) + { + // TODO: Implement properly. + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java b/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java new file mode 100644 index 000000000..2dfcdbdec --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/VolatileImageGraphics.java @@ -0,0 +1,325 @@ +/* VolatileImageGraphics.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.gtk; + +import java.awt.AlphaComposite; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Point; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.WritableRaster; +import java.util.Hashtable; + +public class VolatileImageGraphics extends ComponentGraphics +{ + private GtkVolatileImage owner; + private BufferedImage buffer; + + public VolatileImageGraphics(GtkVolatileImage img) + { + this.owner = img; + cairo_t = initFromVolatile( owner.nativePointer ); + setup( cairo_t ); + } + + private VolatileImageGraphics(VolatileImageGraphics copy) + { + this.owner = copy.owner; + cairo_t = initFromVolatile(owner.nativePointer); + copy( copy, cairo_t ); + } + + public void copyAreaImpl(int x, int y, int width, int height, int dx, int dy) + { + owner.copyArea(x, y, width, height, dx, dy); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + GraphicsConfiguration conf; + if (owner.component != null) + { + conf = owner.component.getGraphicsConfiguration(); + } + else + { + return java.awt.GraphicsEnvironment.getLocalGraphicsEnvironment() + .getDefaultScreenDevice().getDefaultConfiguration(); + } + return conf; + } + + public Graphics create() + { + return new VolatileImageGraphics( this ); + } + + public void draw(Shape s) + { + if (comp == null || comp instanceof AlphaComposite) + super.draw(s); + + // Custom composite + else + { + // Draw operation to temporary buffer + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setColor(this.getColor()); + g2d.setStroke(this.getStroke()); + g2d.draw(s); + + drawComposite(s.getBounds2D(), null); + } + } + + public void fill(Shape s) + { + if (comp == null || comp instanceof AlphaComposite) + super.fill(s); + + // Custom composite + else + { + // Draw operation to temporary buffer + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setPaint(this.getPaint()); + g2d.setColor(this.getColor()); + g2d.fill(s); + + drawComposite(s.getBounds2D(), null); + } + } + + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + if (comp == null || comp instanceof AlphaComposite) + super.drawGlyphVector(gv, x, y); + + // Custom composite + else + { + // Draw operation to temporary buffer + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + + g2d.setPaint(this.getPaint()); + g2d.setColor(this.getColor()); + g2d.drawGlyphVector(gv, x, y); + + Rectangle2D bounds = gv.getLogicalBounds(); + bounds = new Rectangle2D.Double(x + bounds.getX(), y + bounds.getY(), + bounds.getWidth(), bounds.getHeight()); + drawComposite(bounds, null); + } + } + + protected boolean drawImage(Image img, AffineTransform xform, + Color bgcolor, ImageObserver obs) + { + if (comp == null || comp instanceof AlphaComposite) + return super.drawImage(img, xform, bgcolor, obs); + + // Custom composite + else + { + // Get buffered image of source + if( !(img instanceof BufferedImage) ) + { + ImageProducer source = img.getSource(); + if (source == null) + return false; + img = Toolkit.getDefaultToolkit().createImage(source); + } + BufferedImage bImg = (BufferedImage) img; + + // Find dimensions of translation + Point2D origin = new Point2D.Double(bImg.getMinX(), bImg.getMinY()); + Point2D pt = new Point2D.Double(bImg.getWidth(), bImg.getHeight()); + if (xform != null) + { + origin = xform.transform(origin, origin); + pt = xform.transform(pt, pt); + } + + // Create buffer and draw image + createBuffer(); + + Graphics2D g2d = (Graphics2D)buffer.getGraphics(); + g2d.setRenderingHints(this.getRenderingHints()); + g2d.drawImage(img, xform, obs); + + // Perform compositing from buffer to screen + return drawComposite(new Rectangle2D.Double((int)origin.getX(), + (int)origin.getY(), + (int)pt.getX(), + (int)pt.getY()), + obs); + } + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + if (img instanceof GtkVolatileImage + && (comp == null || comp instanceof AlphaComposite)) + { + owner.drawVolatile( ((GtkVolatileImage)img).nativePointer, + x, y, + ((GtkVolatileImage)img).width, + ((GtkVolatileImage)img).height ); + return true; + } + return super.drawImage( img, x, y, observer ); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) + { + if ((img instanceof GtkVolatileImage) + && (comp == null || comp instanceof AlphaComposite)) + { + owner.drawVolatile( ((GtkVolatileImage)img).nativePointer, + x, y, width, height ); + return true; + } + return super.drawImage( img, x, y, width, height, observer ); + } + + protected Rectangle2D getRealBounds() + { + return new Rectangle2D.Double(0, 0, owner.width, owner.height); + } + + private boolean drawComposite(Rectangle2D bounds, ImageObserver observer) + { + // Clip source to visible areas that need updating + Rectangle2D clip = this.getClipBounds(); + Rectangle2D.intersect(bounds, clip, bounds); + + BufferedImage buffer2 = buffer; + if (!bounds.equals(buffer2.getRaster().getBounds())) + buffer2 = buffer2.getSubimage((int)bounds.getX(), (int)bounds.getY(), + (int)bounds.getWidth(), + (int)bounds.getHeight()); + + // Get current on-screen pixels (destination) and clip to bounds + BufferedImage current = owner.getSnapshot(); + + double[] points = new double[] {bounds.getX(), bounds.getY(), + bounds.getMaxX(), bounds.getMaxY()}; + transform.transform(points, 0, points, 0, 2); + + Rectangle2D deviceBounds = new Rectangle2D.Double(points[0], points[1], + points[2] - points[0], + points[3] - points[1]); + Rectangle2D.intersect(deviceBounds, this.getClipInDevSpace(), deviceBounds); + + current = current.getSubimage((int)deviceBounds.getX(), + (int)deviceBounds.getY(), + (int)deviceBounds.getWidth(), + (int)deviceBounds.getHeight()); + + // Perform actual composite operation + compCtx.compose(buffer2.getRaster(), current.getRaster(), + buffer2.getRaster()); + + // This MUST call directly into the "action" method in CairoGraphics2D, + // not one of the wrappers, to ensure that the composite isn't processed + // more than once! + Composite oldComp = comp; // so that ComponentGraphics doesn't + comp = null; // process the composite again + boolean rv = super.drawImage(buffer2, + AffineTransform.getTranslateInstance(bounds.getX(), + bounds.getY()), + null, null); + comp = oldComp; + + return rv; + } + + private void createBuffer() + { + if (buffer == null) + { + WritableRaster rst; + rst = Raster.createWritableRaster(GtkVolatileImage.createGdkSampleModel(owner.width, + owner.height), + new Point(0,0)); + + buffer = new BufferedImage(GtkVolatileImage.gdkColorModel, rst, + GtkVolatileImage.gdkColorModel.isAlphaPremultiplied(), + new Hashtable()); + } + else + { + Graphics2D g2d = ((Graphics2D)buffer.getGraphics()); + + g2d.setBackground(new Color(0,0,0,0)); + g2d.clearRect(0, 0, buffer.getWidth(), buffer.getHeight()); + } + } + + protected ColorModel getNativeCM() + { + // We should really return GtkVolatileImage.gdkColorModel , + // but CairoGraphics2D doesn't handle alpha premultiplication properly (see + // the fixme in drawImage) so we use the naive Cairo model instead to trick + // the compositing context. + // Because getNativeCM() == getBufferCM() for this peer, it doesn't break. + return CairoSurface.cairoCM_pre; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/gtk/package.html b/libjava/classpath/gnu/java/awt/peer/gtk/package.html new file mode 100644 index 000000000..8dd4dd892 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/gtk/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.awt.peer.gtk + + +

This package implements the GTK peer for java.awt.

+ + + diff --git a/libjava/classpath/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java new file mode 100644 index 000000000..401b895b8 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/headless/HeadlessGraphicsEnvironment.java @@ -0,0 +1,118 @@ +/* HeadlessGraphicsEnvironment.java -- A graphics environment for headless mode + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.headless; + +import gnu.java.awt.java2d.RasterGraphics; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.image.BufferedImage; +import java.awt.image.Raster; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.Locale; + +public class HeadlessGraphicsEnvironment + extends GraphicsEnvironment +{ + + public Graphics2D createGraphics(BufferedImage image) + { + Graphics2D g2d; + try + { + // Try to get a CairoGraphics (accellerated) when available. Do this + // via reflection to avoid having a hard compile time dependency. + Class cairoSurfaceCl = + Class.forName("gnu.java.awt.peer.gtk.CairoSurface"); + Raster raster = image.getRaster(); + if (cairoSurfaceCl.isInstance(raster)) + { + Method getGraphicsM = cairoSurfaceCl.getMethod("getGraphics", + new Class[0]); + g2d = (Graphics2D) getGraphicsM.invoke(raster, new Object[0]); + } + else + { + Class bigCl = + Class.forName("gnu.java.awt.peer.gtk.BufferedImageGraphics"); + Constructor bigC = + bigCl.getConstructor(new Class[]{BufferedImage.class }); + g2d = (Graphics2D) bigC.newInstance(new Object[]{ image}); + } + } + catch (Exception ex) + { + g2d = new RasterGraphics(image.getRaster(), image.getColorModel()); + } + return g2d; + } + + public Font[] getAllFonts() + { + // FIXME: Implement. + return null; + } + + public String[] getAvailableFontFamilyNames() + { + // FIXME: Implement. + return null; + } + + public String[] getAvailableFontFamilyNames(Locale l) + { + // FIXME: Implement. + return null; + } + + public GraphicsDevice getDefaultScreenDevice() + { + throw new HeadlessException(); + } + + public GraphicsDevice[] getScreenDevices() + { + throw new HeadlessException(); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/headless/HeadlessToolkit.java b/libjava/classpath/gnu/java/awt/peer/headless/HeadlessToolkit.java new file mode 100644 index 000000000..58b5f3334 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/headless/HeadlessToolkit.java @@ -0,0 +1,385 @@ +/* HeadlessToolkit.java -- A toolkit for headless mode + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.headless; + +import gnu.java.awt.ClasspathToolkit; +import gnu.java.awt.EmbeddedWindow; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.peer.EmbeddedWindowPeer; + +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Image; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.PrintJob; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Window; +import java.awt.datatransfer.Clipboard; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.im.InputMethodHighlight; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.ButtonPeer; +import java.awt.peer.CanvasPeer; +import java.awt.peer.CheckboxMenuItemPeer; +import java.awt.peer.CheckboxPeer; +import java.awt.peer.ChoicePeer; +import java.awt.peer.DialogPeer; +import java.awt.peer.FileDialogPeer; +import java.awt.peer.FontPeer; +import java.awt.peer.FramePeer; +import java.awt.peer.LabelPeer; +import java.awt.peer.ListPeer; +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.PopupMenuPeer; +import java.awt.peer.RobotPeer; +import java.awt.peer.ScrollPanePeer; +import java.awt.peer.ScrollbarPeer; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.WindowPeer; +import java.io.InputStream; +import java.net.URL; +import java.util.Map; +import java.util.Properties; + +public class HeadlessToolkit + extends ClasspathToolkit +{ + + /** + * The graphics environment for headless graphics. + */ + private HeadlessGraphicsEnvironment graphicsEnv; + + public void beep() + { + // TODO Auto-generated method stub + + } + + public int checkImage(Image image, int width, int height, + ImageObserver observer) + { + // TODO Auto-generated method stub + return 0; + } + + protected ButtonPeer createButton(Button target) + { + throw new HeadlessException(); + } + + protected CanvasPeer createCanvas(Canvas target) + { + throw new HeadlessException(); + } + + protected CheckboxPeer createCheckbox(Checkbox target) + { + throw new HeadlessException(); + } + + protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) + { + throw new HeadlessException(); + } + + protected ChoicePeer createChoice(Choice target) + { + throw new HeadlessException(); + } + + protected DialogPeer createDialog(Dialog target) + { + throw new HeadlessException(); + } + + public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e) + { + throw new HeadlessException(); + } + + protected FileDialogPeer createFileDialog(FileDialog target) + { + throw new HeadlessException(); + } + + protected FramePeer createFrame(Frame target) + { + throw new HeadlessException(); + } + + public Image createImage(String filename) + { + // FIXME: Implement. + return null; + } + + public Image createImage(URL url) + { + // FIXME: Implement. + return null; + } + + public Image createImage(ImageProducer producer) + { + // FIXME: Implement. + return null; + } + + public Image createImage(byte[] data, int offset, int len) + { + // TODO Auto-generated method stub + return null; + } + + protected LabelPeer createLabel(Label target) + { + throw new HeadlessException(); + } + + protected ListPeer createList(List target) + { + throw new HeadlessException(); + } + + protected MenuPeer createMenu(Menu target) + { + throw new HeadlessException(); + } + + protected MenuBarPeer createMenuBar(MenuBar target) + { + throw new HeadlessException(); + } + + protected MenuItemPeer createMenuItem(MenuItem target) + { + throw new HeadlessException(); + } + + protected PanelPeer createPanel(Panel target) + { + throw new HeadlessException(); + } + + protected PopupMenuPeer createPopupMenu(PopupMenu target) + { + throw new HeadlessException(); + } + + protected ScrollPanePeer createScrollPane(ScrollPane target) + { + throw new HeadlessException(); + } + + protected ScrollbarPeer createScrollbar(Scrollbar target) + { + throw new HeadlessException(); + } + + protected TextAreaPeer createTextArea(TextArea target) + { + throw new HeadlessException(); + } + + protected TextFieldPeer createTextField(TextField target) + { + throw new HeadlessException(); + } + + protected WindowPeer createWindow(Window target) + { + throw new HeadlessException(); + } + + public ColorModel getColorModel() + { + // TODO Auto-generated method stub + return null; + } + + public String[] getFontList() + { + // TODO Auto-generated method stub + return null; + } + + public FontMetrics getFontMetrics(Font name) + { + // TODO Auto-generated method stub + return null; + } + + protected FontPeer getFontPeer(String name, int style) + { + // TODO Auto-generated method stub + return null; + } + + public Image getImage(String name) + { + // TODO Auto-generated method stub + return null; + } + + public Image getImage(URL url) + { + // TODO Auto-generated method stub + return null; + } + + public PrintJob getPrintJob(Frame frame, String title, Properties props) + { + // TODO Auto-generated method stub + return null; + } + + public int getScreenResolution() + { + throw new HeadlessException(); + } + + public Dimension getScreenSize() + { + throw new HeadlessException(); + } + + public Clipboard getSystemClipboard() + { + throw new HeadlessException(); + } + + protected EventQueue getSystemEventQueueImpl() + { + throw new HeadlessException(); + } + + public Map mapInputMethodHighlight(InputMethodHighlight highlight) + { + // TODO Auto-generated method stub + return null; + } + + public boolean prepareImage(Image image, int width, int height, + ImageObserver observer) + { + // TODO Auto-generated method stub + return false; + } + + public void sync() + { + // TODO Auto-generated method stub + + } + + public EmbeddedWindowPeer createEmbeddedWindow(EmbeddedWindow w) + { + throw new HeadlessException(); + } + + public Font createFont(int format, InputStream stream) + { + // TODO Auto-generated method stub + return null; + } + + public RobotPeer createRobot(GraphicsDevice screen) throws AWTException + { + throw new HeadlessException(); + } + + public ClasspathFontPeer getClasspathFontPeer(String name, Map attrs) + { + // TODO Auto-generated method stub + return null; + } + + public GraphicsEnvironment getLocalGraphicsEnvironment() + { + if (graphicsEnv == null) + graphicsEnv = new HeadlessGraphicsEnvironment(); + return graphicsEnv; + } + + @Override + public boolean isModalExclusionTypeSupported + (Dialog.ModalExclusionType modalExclusionType) + { + return false; + } + + @Override + public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) + { + return false; + } + + +} diff --git a/libjava/classpath/gnu/java/awt/peer/package.html b/libjava/classpath/gnu/java/awt/peer/package.html new file mode 100644 index 000000000..846759a28 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.awt.peer + + +

+ + + diff --git a/libjava/classpath/gnu/java/awt/peer/qt/MainQtThread.java b/libjava/classpath/gnu/java/awt/peer/qt/MainQtThread.java new file mode 100644 index 000000000..bee979ac7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/MainQtThread.java @@ -0,0 +1,84 @@ +/* MainQtThread.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +/** + * This Thread is the main Qt thread. + * + * It doesn't appear to do much here, since all custom code executed by + * this thread is injected into Qt's main event loop through the (native) + * MainThreadInterface class. + */ +public class MainQtThread extends Thread +{ + long QApplicationPointer; + long mainThreadInterface; + String theme; + private boolean running; + private boolean doublebuffer; + + public MainQtThread( String theme, boolean doublebuffer ) + { + this.theme = theme; + this.doublebuffer = doublebuffer; + running = false; + } + + public boolean isRunning() + { + return running; + } + + /** + * Creates the QApplication + */ + public native long init(String theme, boolean doublebuffer); + + /** + * Runs the QApplication (doesn't return.) + */ + public native void exec(long ptr); + + public void run() + { + QApplicationPointer = init(theme, doublebuffer); + running = true; + exec(QApplicationPointer); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/NativeWrapper.java b/libjava/classpath/gnu/java/awt/peer/qt/NativeWrapper.java new file mode 100644 index 000000000..706e0df6c --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/NativeWrapper.java @@ -0,0 +1,43 @@ +/* NativeWrapper.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +public class NativeWrapper +{ + protected long nativeObject; +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QMatrix.java b/libjava/classpath/gnu/java/awt/peer/qt/QMatrix.java new file mode 100644 index 000000000..ca4d55b59 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QMatrix.java @@ -0,0 +1,72 @@ +/* QMatrix.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.geom.AffineTransform; + +/** + * A simple wrapper class for a QMatrix, + * interfacing it to an AffineTransform. + */ +public class QMatrix extends NativeWrapper +{ + + public QMatrix( AffineTransform t ) + { + double[] matrix = new double[6]; + t.getMatrix( matrix ); + init( matrix[0], matrix[1], matrix[2], matrix[3], matrix[4], matrix[5] ); + } + + private native void init(double m00, double m10, double m01, double m11, + double m02, double m12 ); + + private native double[] getMatrix(); + + public AffineTransform getTransform() + { + return new AffineTransform( getMatrix() ); + } + + public native void dispose(); + + public void finalize() + { + dispose(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QPainterPath.java b/libjava/classpath/gnu/java/awt/peer/qt/QPainterPath.java new file mode 100644 index 000000000..848b10497 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QPainterPath.java @@ -0,0 +1,140 @@ +/* QPainterPath.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.PathIterator; +import java.awt.geom.GeneralPath; + +/** + * A simple wrapper class for a QPainterPath, + * createable from an AWT Shape + */ +public class QPainterPath extends NativeWrapper +{ + QPainterPath() + { + } + + public QPainterPath( Shape s ) + { + PathIterator pi = s.getPathIterator( new AffineTransform() ); + double[] coords = new double[6]; + + init( pi.getWindingRule() ); + + while( !pi.isDone() ) + { + switch( pi.currentSegment(coords) ) + { + case PathIterator.SEG_MOVETO: + moveTo( coords[0], coords[1] ); + break; + + case PathIterator.SEG_CLOSE: + close(); + break; + + case PathIterator.SEG_LINETO: + lineTo( coords[0], coords[1] ); + break; + + case PathIterator.SEG_QUADTO: + quadTo( coords[0], coords[1], coords[2], coords[3] ); + break; + + case PathIterator.SEG_CUBICTO: + cubicTo( coords[0], coords[1], + coords[2], coords[3], + coords[4], coords[5] ); + break; + } + pi.next(); + } + } + + /** + * Constructor for rectangles. + */ + public QPainterPath( double x, double y, double w, double h ) + { + init(PathIterator.WIND_EVEN_ODD); + moveTo( x, y ); + lineTo( x + w, y ); + lineTo( x + w, y + h ); + lineTo( x , y + h ); + lineTo( x, y ); + close(); + } + + /** + * Constructor for lines. + */ + public QPainterPath( double x1, double y1, double x2, double y2, boolean s ) + { + init(PathIterator.WIND_EVEN_ODD); + moveTo( x1, y1 ); + lineTo( x2, y2 ); + } + + /** + * Returns the QPainterPath as a GeneralPath + */ + public native GeneralPath getPath(); + + private native void init(int windingRule); + + private native void moveTo(double x, double y); + + private native void close(); + + private native void lineTo(double x, double y); + + private native void quadTo(double x1, double y1, double x2, double y2); + + private native void cubicTo(double x1, double y1, double x2, double y2, + double x3, double y3); + + public native void dispose(); + + public void finalize() + { + dispose(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QPen.java b/libjava/classpath/gnu/java/awt/peer/qt/QPen.java new file mode 100644 index 000000000..aee308c26 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QPen.java @@ -0,0 +1,70 @@ +/* QPen.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Stroke; +import java.awt.BasicStroke; + +/** + * A simple wrapper class for a QPen, + * interfacing it to an BasicStroke. + */ +public class QPen extends NativeWrapper +{ + + public QPen( Stroke stroke ) + { + if( !( stroke instanceof BasicStroke ) ) + throw new IllegalArgumentException("Not a basic stroke."); + + BasicStroke s = (BasicStroke)stroke; + if(s.getDashArray() != null) + throw new IllegalArgumentException("Can't handle dashed strokes."); + + init(s.getLineWidth(), s.getEndCap(), s.getLineJoin(), s.getMiterLimit()); + } + + private native void init(double width, int cap, int join, double miterlimit); + + public native void dispose(); + + public void finalize() + { + dispose(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtAudioClip.java b/libjava/classpath/gnu/java/awt/peer/qt/QtAudioClip.java new file mode 100644 index 000000000..ae2e350eb --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtAudioClip.java @@ -0,0 +1,110 @@ +/* QtAudioClip.java -- Qt implementation of the applet AudioClip interface + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.applet.AudioClip; +import java.awt.Toolkit; +import java.io.File; +import java.io.IOException; +import java.net.URL; + +/** + * Implementation of the applet AudioClip interface on a Qt + * QSound object. + */ +public class QtAudioClip extends NativeWrapper implements AudioClip +{ + private static Toolkit t = null; + + public QtAudioClip(String filename) + { + checkForQt(); + File f = new File(filename); + try + { + String fn = f.getCanonicalPath(); + loadClip( fn ); + } + catch(IOException e) + { + } + } + + public QtAudioClip(URL url) + { + + } + + private native void loadClip(String filename); + + private native void play(boolean looped); + + private native boolean isAvailable(); + + /** + * Checks that Qt and sound is available. + */ + private void checkForQt() + { + if( t == null ) + t = Toolkit.getDefaultToolkit(); + if( !( t instanceof QtToolkit) ) + throw new IllegalStateException("This requires Qt peers."); + } + + // *************** Public methods ******************* + + public void loop() + { + play( true ); + } + + public void play() + { + play( false ); + } + + public native void stop(); + + public native void dispose(); + + public void finalize() + { + dispose(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtButtonPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtButtonPeer.java new file mode 100644 index 000000000..6722eb285 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtButtonPeer.java @@ -0,0 +1,75 @@ +/* QtButtonPeer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Button; +import java.awt.event.ActionEvent; +import java.awt.peer.ButtonPeer; + +public class QtButtonPeer extends QtComponentPeer implements ButtonPeer +{ + public QtButtonPeer( QtToolkit kit, Button owner ) + { + super( kit, owner ); + } + + public native void init(); + + protected void setup() + { + super.setup(); + setLabel( ((Button)owner).getLabel() ); + } + + /** + * Callback for button click events + */ + void fireClick(int modifiers) + { + ActionEvent e = new ActionEvent(owner, + ActionEvent.ACTION_PERFORMED, + ((Button)owner).getActionCommand(), + System.currentTimeMillis(), + modifiers); + QtToolkit.eventQueue.postEvent(e); + } + + // ************ Public methods ********************* + + public native void setLabel( String label ); +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtCanvasPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtCanvasPeer.java new file mode 100644 index 000000000..2367cd066 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtCanvasPeer.java @@ -0,0 +1,65 @@ +/* QtCanvasPeer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Canvas; +import java.awt.Dimension; +import java.awt.peer.CanvasPeer; + +public class QtCanvasPeer extends QtComponentPeer implements CanvasPeer +{ + public QtCanvasPeer( QtToolkit kit, Canvas owner ) + { + super( kit, owner ); + } + + public native void init(); + + protected void setup() + { + super.setup(); + } + + /** + * Overloaded, because a Canvas doesn't have a preferred size. + */ + public Dimension getPreferredSize() + { + return owner.getSize(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtCheckboxPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtCheckboxPeer.java new file mode 100644 index 000000000..37fb51c48 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtCheckboxPeer.java @@ -0,0 +1,111 @@ +/* QtCheckboxPeer.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.event.ItemEvent; +import java.awt.peer.CheckboxPeer; +import java.util.WeakHashMap; + +public class QtCheckboxPeer extends QtComponentPeer implements CheckboxPeer +{ + private CheckboxGroup group; + + // Map QButtonGroup<->CheckboxGroup + private static WeakHashMap groupMap; + + static + { + groupMap = new WeakHashMap(); + } + + public QtCheckboxPeer( QtToolkit kit, Checkbox owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setCheckboxGroup( ((Checkbox)owner).getCheckboxGroup() ); + setLabel( ((Checkbox)owner).getLabel() ); + setState( ((Checkbox)owner).getState() ); + } + + private void fireToggle(boolean checked) + { + if (group == null) + ((Checkbox)owner).setState( checked ); + else + if ( checked ) + group.setSelectedCheckbox((Checkbox)owner); + + int sel = checked ? ItemEvent.SELECTED : ItemEvent.DESELECTED; + ItemEvent e = new ItemEvent((Checkbox)owner, + ItemEvent.ITEM_STATE_CHANGED, + ((Checkbox)owner).getLabel(), + sel); + QtToolkit.eventQueue.postEvent(e); + } + + // ************ Public methods ********************* + + public void setCheckboxGroup( CheckboxGroup group ) + { + if(this.group == group) + return; + + // if we change from a checkbox to a radio button or vice versa + if((this.group == null) != (group == null)) + { + this.group = group; + callInit(); + setup(); + } + + this.group = group; + } + + public native void setLabel( String label ); + + public native void setState( boolean state ); + +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtChoicePeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtChoicePeer.java new file mode 100644 index 000000000..d279468cd --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtChoicePeer.java @@ -0,0 +1,93 @@ +/* QtChoicePeer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Choice; +import java.awt.event.ItemEvent; +import java.awt.peer.ChoicePeer; + +public class QtChoicePeer extends QtComponentPeer implements ChoicePeer +{ + public QtChoicePeer( QtToolkit kit, Choice owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + + Choice c = (Choice) owner; + int n = c.getItemCount(); + for ( int i = 0; i < n ; i++ ) + add( c.getItem( i ), i ); + select( c.getSelectedIndex() ); + } + + private void fireChoice( int index ) + { + ((Choice)owner).select( index ); + ItemEvent e = new ItemEvent((Choice)owner, + ItemEvent.ITEM_STATE_CHANGED, + ((Choice)owner).getItem(index), + ItemEvent.SELECTED); + QtToolkit.eventQueue.postEvent(e); + } + + // ************ Public methods ********************* + + public native void add( String item, int index ); + + public void addItem( String item, int index ) + { + add(item, index); + } + + public native void remove( int index ); + + public void removeAll() + { + int n = ((Choice)owner).getItemCount(); + for (int i = 0; i < n; i++) + remove( i ); + } + + public native void select( int index ); +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtComponentGraphics.java b/libjava/classpath/gnu/java/awt/peer/qt/QtComponentGraphics.java new file mode 100644 index 000000000..27e12e659 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtComponentGraphics.java @@ -0,0 +1,120 @@ +/* QtComponentGraphics.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Color; +import java.awt.GraphicsConfiguration; +import java.awt.Graphics; +import java.awt.Rectangle; + +/** + * QtComponentPainter is a Graphics2D context for painting directly to AWT + * components. They require an existing QPainter object (the one passed into + * the native paint method), and are created there (ONLY). + * + * Since this context does direct on-screen drawing it is NOT thread-safe, + * and should NOT be used outside the thread in which it was created. + * + * In other words, + * this is intended for use by QtComponentPeer.paintEvent() only. + * + */ +public class QtComponentGraphics extends QtGraphics +{ + private QtComponentPeer peer; + + /** + * Creates a new ComponentGraphics from an *existing* QPainter object. + * + * @param ptr the pointer to the QPainter object. + */ + public QtComponentGraphics(long ptr, QtComponentPeer component, + int x, int y, int w, int h) + { + nativeObject = ptr; + peer = component; + + Rectangle r = new Rectangle(x, y, w, h); + initialClip = r; + + setAlpha( 1.0 ); + Color c = component.owner.getBackground(); + if(c == null) + setBackground(Color.white); + else + setBackground( c ); + + c = component.owner.getForeground(); + if(c == null) + setColor( Color.black ); + else + setColor( c ); + setup(); + setClip( initialClip ); + } + + /** + * Copying constructor + */ + QtComponentGraphics( QtComponentGraphics g ) + { + super( g ); // Slalom is fun + } + + public Graphics create() + { + return new QtComponentGraphics( this ); + } + + /** + * This is a tricky one + */ + public void copyArea(int x, int y, int width, int height, + int dx, int dy) + { + // FIXME + } + + /** + * Returns the GraphicsConfiguration of the context component. + */ + public GraphicsConfiguration getDeviceConfiguration() + { + return peer.getGraphicsConfiguration(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtComponentPeer.java new file mode 100644 index 000000000..16149b2e6 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtComponentPeer.java @@ -0,0 +1,834 @@ +/* QtComponentPeer.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.BufferCapabilities; +import java.awt.Component; +import java.awt.Color; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Image; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.KeyboardFocusManager; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.peer.ComponentPeer; +import java.awt.peer.ContainerPeer; +import java.awt.image.ColorModel; +import java.awt.image.VolatileImage; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.event.ComponentEvent; // 100% +import java.awt.event.FocusEvent; // 100% +import java.awt.event.InputEvent; // (abstract) +import java.awt.event.KeyEvent; // 2/3 +import java.awt.event.MouseEvent; // 70%? +import java.awt.event.PaintEvent; // Yup. +import java.awt.event.WindowEvent; // 2/ 12 +import java.util.Timer; +import java.util.TimerTask; + +public class QtComponentPeer extends NativeWrapper implements ComponentPeer +{ + + /** + * Popup trigger button, may differ between platforms + */ + protected static final int POPUP_TRIGGER = 3; + + /** + * The toolkit which manufactured this peer. + */ + protected QtToolkit toolkit; + + /** + * The component which owns this peer. + */ + Component owner; + + /** + * Classpath updates our eventMask. + */ + private long eventMask; + + /** + * if the thing has mouse motion listeners or not. + */ + private boolean hasMotionListeners; + + /** + * The component's double buffer for off-screen drawing. + */ + protected QtImage backBuffer; + + protected long qtApp; + + private boolean settingUp; + + private boolean ignoreResize = false; + + QtComponentPeer( QtToolkit kit, Component owner ) + { + this.owner = owner; + this.toolkit = kit; + qtApp = QtToolkit.guiThread.QApplicationPointer; + nativeObject = 0; + synchronized(this) + { + callInit(); // Calls the init method FROM THE MAIN THREAD. + try + { + wait(); // Wait for the thing to be created. + } + catch(InterruptedException e) + { + } + } + setup(); + hasMotionListeners = false; + } + + protected native void callInit(); + + /** + * Init does the creation of native widgets, it is therefore + * called from the main thread. (the constructor waits for this to happen.) + */ + protected void init() + { + } + + protected void setup() + { + settingUp = true; + if (owner != null) + { + if (owner instanceof javax.swing.JComponent) + setBackground(owner.getBackground()); + else + owner.setBackground(getNativeBackground()); + + if (owner.getForeground() != null) + setForeground(owner.getForeground()); + else + setForeground( Color.black ); + + if (owner.getCursor() != null) + if (owner.getCursor().getType() != Cursor.DEFAULT_CURSOR) + setCursor(owner.getCursor()); + + if (owner.getFont() != null) + setFont(owner.getFont()); + + setEnabled( owner.isEnabled() ); + + backBuffer = null; + updateBounds(); + + setVisible( owner.isVisible() ); + QtToolkit.repaintThread.queueComponent(this); + } + settingUp = false; + } + + native void QtUpdate(); + native void QtUpdateArea( int x, int y, int w, int h ); + private synchronized native void disposeNative(); + private native void setGround( int r, int g, int b, boolean isForeground ); + private native void setBoundsNative( int x, int y, int width, int height ); + private native void setCursor( int ctype ); + private native Color getNativeBackground(); + private native void setFontNative( QtFontPeer fp ); + private native int whichScreen(); + private native void reparentNative( QtContainerPeer parent ); + private native void getLocationOnScreenNative( Point p ); + + private boolean drawableComponent() + { + return ((this instanceof QtContainerPeer && + !(this instanceof QtScrollPanePeer)) || + (this instanceof QtCanvasPeer)); + } + + void updateBounds() + { + Rectangle r = owner.getBounds(); + setBounds( r.x, r.y, r.width, r.height ); + } + + synchronized void updateBackBuffer(int width, int height) + { + if(width <= 0 || height <= 0) + return; + + if( !drawableComponent() && backBuffer == null) + return; + + if( backBuffer != null ) + { + if( width < backBuffer.width && height < backBuffer.height ) + return; + backBuffer.dispose(); + } + backBuffer = new QtImage(width, height); + } + + + // ************ Event methods ********************* + + /** + * Window closing event + */ + protected void closeEvent() + { + if (owner instanceof Window) + { + WindowEvent e = new WindowEvent((Window)owner, + WindowEvent.WINDOW_CLOSING); + QtToolkit.eventQueue.postEvent(e); + } + } + + protected void enterEvent(int modifiers, int x, int y, int dummy) + { + MouseEvent e = new MouseEvent(owner, + MouseEvent.MOUSE_ENTERED, + System.currentTimeMillis(), + (modifiers & 0x2FF), x, y, 0, false); + QtToolkit.eventQueue.postEvent(e); + } + + protected void focusInEvent() + { + FocusEvent e = new FocusEvent(owner, FocusEvent.FOCUS_GAINED); + QtToolkit.eventQueue.postEvent(e); + } + + protected void focusOutEvent() + { + FocusEvent e = new FocusEvent(owner, FocusEvent.FOCUS_LOST); + QtToolkit.eventQueue.postEvent(e); + } + + protected void keyPressEvent(int modifiers, int code, int unicode, int dummy) + { + KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager (); + KeyEvent e = new KeyEvent(owner, + KeyEvent.KEY_PRESSED, + System.currentTimeMillis(), + modifiers, code, (char)(unicode & 0xFFFF), + KeyEvent.KEY_LOCATION_UNKNOWN); + if (!manager.dispatchEvent (e)) + QtToolkit.eventQueue.postEvent(e); + } + + protected void keyReleaseEvent(int modifiers, int code, int unicode, int dummy) + { + KeyEvent e = new KeyEvent(owner, + KeyEvent.KEY_RELEASED, + System.currentTimeMillis(), + modifiers, code, (char)(unicode & 0xFFFF), + KeyEvent.KEY_LOCATION_UNKNOWN); + QtToolkit.eventQueue.postEvent(e); + } + + protected void leaveEvent(int modifiers, int x, int y, int dummy) + { + MouseEvent e = new MouseEvent(owner, + MouseEvent.MOUSE_EXITED, + System.currentTimeMillis(), + (modifiers & 0x2FF), x, y, 0, false); + QtToolkit.eventQueue.postEvent(e); + } + + // FIXME: Coalesce press-release events into clicks. + protected void mouseDoubleClickEvent( int modifiers, int x, int y, int clickCount) + { + if( (eventMask & AWTEvent.MOUSE_EVENT_MASK) == 0 ) + return; + int button = 0; + if((modifiers & InputEvent.BUTTON1_DOWN_MASK) == + InputEvent.BUTTON1_DOWN_MASK) button = 1; + if((modifiers & InputEvent.BUTTON2_DOWN_MASK) == + InputEvent.BUTTON2_DOWN_MASK) button = 2; + if((modifiers & InputEvent.BUTTON3_DOWN_MASK) == + InputEvent.BUTTON3_DOWN_MASK) button = 3; + MouseEvent e = new MouseEvent(owner, + MouseEvent.MOUSE_CLICKED, + System.currentTimeMillis(), + (modifiers & 0x2FF), x, y, clickCount, + false, button); + QtToolkit.eventQueue.postEvent(e); + } + + protected void mouseMoveEvent( int modifiers, int x, int y, int clickCount) + { + if( (eventMask & AWTEvent.MOUSE_EVENT_MASK) == 0 ) + return; + + int button = 0; + if((modifiers & InputEvent.BUTTON1_DOWN_MASK) == + InputEvent.BUTTON1_DOWN_MASK) button = 1; + if((modifiers & InputEvent.BUTTON2_DOWN_MASK) == + InputEvent.BUTTON2_DOWN_MASK) button = 2; + if((modifiers & InputEvent.BUTTON3_DOWN_MASK) == + InputEvent.BUTTON3_DOWN_MASK) button = 3; + + int type = (button != 0) ? + MouseEvent.MOUSE_DRAGGED :MouseEvent.MOUSE_MOVED; + + MouseEvent e = new MouseEvent(owner, + type, + System.currentTimeMillis(), + (modifiers & 0x2FF), x, y, clickCount, + false, button); + QtToolkit.eventQueue.postEvent(e); + } + + protected void mousePressEvent( int modifiers, int x, int y, int clickCount) + { + if( (eventMask & AWTEvent.MOUSE_EVENT_MASK) == 0 ) + return; + int button = 0; + if((modifiers & InputEvent.BUTTON1_DOWN_MASK) == + InputEvent.BUTTON1_DOWN_MASK) button = 1; + if((modifiers & InputEvent.BUTTON2_DOWN_MASK) == + InputEvent.BUTTON2_DOWN_MASK) button = 2; + if((modifiers & InputEvent.BUTTON3_DOWN_MASK) == + InputEvent.BUTTON3_DOWN_MASK) button = 3; + MouseEvent e = new MouseEvent(owner, + MouseEvent.MOUSE_PRESSED, + System.currentTimeMillis(), + (modifiers & 0x2FF), x, y, clickCount, + ( button == POPUP_TRIGGER ), + button); + QtToolkit.eventQueue.postEvent(e); + } + + protected void mouseReleaseEvent( int modifiers, int x, int y, int clickCount) + { + if( (eventMask & AWTEvent.MOUSE_EVENT_MASK) == 0 ) + return; + int button = 0; + if((modifiers & InputEvent.BUTTON1_DOWN_MASK) == + InputEvent.BUTTON1_DOWN_MASK) button = 1; + if((modifiers & InputEvent.BUTTON2_DOWN_MASK) == + InputEvent.BUTTON2_DOWN_MASK) button = 2; + if((modifiers & InputEvent.BUTTON3_DOWN_MASK) == + InputEvent.BUTTON3_DOWN_MASK) button = 3; + + MouseEvent e = new MouseEvent(owner, + MouseEvent.MOUSE_RELEASED, + System.currentTimeMillis(), + (modifiers & 0x2FF), x, y, clickCount, + false, button); + QtToolkit.eventQueue.postEvent(e); + } + + protected void moveEvent(int x, int y, int oldx, int oldy) + { + if( !ignoreResize ) + { + // Since Component.setLocation calls back to setBounds, + // we need to ignore that. + ignoreResize = true; + owner.setLocation( x, y ); + ignoreResize = false; + } + } + + protected void resizeEvent(int oldWidth, int oldHeight, + int width, int height) + { + if(!(owner instanceof Window)) + return; + updateBackBuffer(width, height); + ignoreResize = true; + owner.setSize(width, height); + ignoreResize = false; + ComponentEvent e = new ComponentEvent(owner, + ComponentEvent.COMPONENT_RESIZED); + QtToolkit.eventQueue.postEvent(e); + QtToolkit.repaintThread.queueComponent(this); + } + + protected void showEvent() + { + if (owner instanceof Window) + { + WindowEvent e = new WindowEvent((Window)owner, + WindowEvent.WINDOW_OPENED); + QtToolkit.eventQueue.postEvent(e); + } + else + { + ComponentEvent e = new ComponentEvent(owner, + ComponentEvent.COMPONENT_SHOWN); + QtToolkit.eventQueue.postEvent(e); + } + } + + protected void hideEvent() + { + ComponentEvent e = new ComponentEvent(owner, + ComponentEvent.COMPONENT_HIDDEN); + QtToolkit.eventQueue.postEvent(e); + } + + // ************ Public methods ********************* + + /** Classpath-specific method */ + public void setEventMask(long x) + { + eventMask = x; + } + + + public boolean canDetermineObscurity() + { + return true; + } + + public int checkImage(Image img, + int w, + int h, + ImageObserver o) + { + return toolkit.checkImage(img, w, h, o); + } + + public void createBuffers(int numBuffers, BufferCapabilities caps) + throws AWTException + { + // FIXME + } + + public Image createImage(ImageProducer producer) + { + return toolkit.createImage(producer); + } + + public Image createImage(int width, int height) + { + return new QtImage(width, height); + } + + public void coalescePaintEvent(PaintEvent e) + { + // FIXME + } + + public VolatileImage createVolatileImage(int w, int h) + { + return new QtVolatileImage( w, h ); + } + + public void destroyBuffers() + { + // FIXME + } + + public void disable() + { + setEnabled(false); + } + + public void dispose() + { + disposeNative(); + if( backBuffer != null ) + backBuffer.dispose(); + } + + public void enable() + { + setEnabled(true); + } + + public void finalize() + { + dispose(); + } + + public void flip(BufferCapabilities.FlipContents contents) + { + } + + public Image getBackBuffer() + { + return backBuffer; + } + + public ColorModel getColorModel() + { + return toolkit.getColorModel(); + } + + public FontMetrics getFontMetrics(Font font) + { + return new QtFontMetrics( font, getGraphics() ); + } + + public Graphics getGraphics() + { + if( backBuffer == null ) + { + Rectangle r = owner.getBounds(); + backBuffer = new QtImage( r.width, r.height ); + } + return backBuffer.getDirectGraphics( this ); + } + + public GraphicsConfiguration getGraphicsConfiguration() + { + int id = whichScreen(); // get the ID of the screen the widget is on. + GraphicsDevice[] devs = QtToolkit.graphicsEnv.getScreenDevices(); + return devs[id].getDefaultConfiguration(); + } + + public Point getLocationOnScreen() + { + Point p = new Point(); + synchronized( p ) + { + getLocationOnScreenNative( p ); + try + { + p.wait(); // Wait for the thing to be created. + } + catch(InterruptedException e) + { + } + } + return p; + } + + private native void getSizeNative(Dimension d, boolean preferred); + + private Dimension getSize(boolean preferred) + { + Dimension d = new Dimension(); + synchronized( d ) + { + getSizeNative(d, preferred); + try + { + d.wait(); // Wait for the thing to be created. + } + catch(InterruptedException e) + { + } + } + return d; + } + + public Dimension getMinimumSize() + { + return getSize( false ); + } + + public Dimension getPreferredSize() + { + return getSize( true ); + } + + public Toolkit getToolkit() + { + return toolkit; + } + + public native boolean handlesWheelScrolling(); + + public void hide() + { + setVisible(false); + } + + public native boolean isFocusable(); + + public boolean isFocusTraversable() + { + // FIXME + return false; + } + + public native boolean isObscured(); + + public Dimension minimumSize() + { + return getMinimumSize(); + } + + public Dimension preferredSize() + { + return getPreferredSize(); + } + + public native void requestFocus(); + + public boolean requestFocus (Component source, boolean bool1, + boolean bool2, long x) + { + // FIXME + return true; + } + + public void reshape(int x, + int y, + int width, + int height) + { + setBounds( x, y, width, height ); + } + + public void setBackground(Color c) + { + if(c == null && !settingUp) + return; + setGround(c.getRed(), c.getGreen(), c.getBlue(), false); + } + + public void setBounds(int x, int y, int width, int height) + { + if( ignoreResize ) + return; + updateBackBuffer(width, height); + QtToolkit.repaintThread.queueComponent(this); + setBoundsNative(x, y, width, height); + } + + public void setCursor(Cursor cursor) + { + if (cursor != null) + setCursor(cursor.getType()); + } + + public native void setEnabled(boolean b); + + public void setFont(Font f) + { + if( f == null || f.getPeer() == null) + throw new IllegalArgumentException("Null font."); + setFontNative( (QtFontPeer)f.getPeer() ); + } + + public void setForeground(Color c) + { + if(c == null && !settingUp) + return; + setGround(c.getRed(), c.getGreen(), c.getBlue(), true); + } + + public native void setVisible(boolean b); + + public void show() + { + setVisible(true); + } + + public void handleEvent (AWTEvent e) + { + int eventID = e.getID(); + Rectangle r; + + switch (eventID) + { + case ComponentEvent.COMPONENT_SHOWN: + QtToolkit.repaintThread.queueComponent(this); + break; + case PaintEvent.PAINT: + case PaintEvent.UPDATE: + r = ((PaintEvent)e).getUpdateRect(); + QtToolkit.repaintThread.queueComponent(this, r.x, r.y, + r.width, r.height); + break; + case KeyEvent.KEY_PRESSED: + break; + case KeyEvent.KEY_RELEASED: + break; + } + } + + /** + * paint() is called back from the native side in response to a native + * repaint event. + */ + public void paint(Graphics g) + { + Rectangle r = g.getClipBounds(); + + if (backBuffer != null) + backBuffer.drawPixelsScaledFlipped ((QtGraphics) g, + 0, 0, 0, /* bg colors */ + false, false, /* no flipping */ + r.x, r.y, r.width, r.height, + r.x, r.y, r.width, r.height, + false ); /* no compositing */ + } + + public void paintBackBuffer() throws InterruptedException + { + if( backBuffer != null ) + { + backBuffer.clear(); + Graphics2D bbg = (Graphics2D)backBuffer.getGraphics(); + owner.paint(bbg); + bbg.dispose(); + } + } + + public void paintBackBuffer(int x, int y, int w, int h) + throws InterruptedException + { + if( backBuffer != null ) + { + Graphics2D bbg = (Graphics2D)backBuffer.getGraphics(); + bbg.setBackground( getNativeBackground() ); + bbg.clearRect(x, y, w, h); + bbg.setClip(x, y, w, h); + owner.paint(bbg); + bbg.dispose(); + } + } + + public boolean prepareImage(Image img, + int w, + int h, + ImageObserver o) + { + return toolkit.prepareImage(img, w, h, o); + } + + public void print(Graphics g) + { + // FIXME + } + + /** + * Schedules a timed repaint. + */ + public void repaint(long tm, + int x, + int y, + int w, + int h) + { + if( tm <= 0 ) + { + QtToolkit.repaintThread.queueComponent(this, x, y, w, h); + return; + } + Timer t = new Timer(); + t.schedule(new RepaintTimerTask(this, x, y, w, h), tm); + } + + /** + * Update the cursor (note that setCursor is usually not called) + */ + public void updateCursorImmediately() + { + if (owner.getCursor() != null) + setCursor(owner.getCursor().getType()); + } + + /** + * Timed repainter + */ + private class RepaintTimerTask extends TimerTask + { + private int x, y, w, h; + private QtComponentPeer peer; + RepaintTimerTask(QtComponentPeer peer, int x, int y, int w, int h) + { + this.x=x; + this.y=y; + this.w=w; + this.h=h; + this.peer=peer; + } + public void run() + { + QtToolkit.repaintThread.queueComponent(peer, x, y, w, h); + } + } + + public native Rectangle getBounds(); + + public void reparent(ContainerPeer parent) + { + if(!(parent instanceof QtContainerPeer)) + throw new IllegalArgumentException("Illegal peer."); + reparentNative((QtContainerPeer)parent); + } + + public void setBounds(int x, int y, int width, int height, int z) + { + // TODO Auto-generated method stub + + } + + public boolean isReparentSupported() + { + return true; + } + + // What does this do, anyway? + public void layout() + { + // TODO Auto-generated method stub + } + + public boolean requestFocus(Component lightweightChild, boolean temporary, + boolean focusedWindowChangeAllowed, + long time, sun.awt.CausedFocusEvent.Cause cause) + { + // TODO: Implement this properly and remove the other requestFocus() + // methods. + return true; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtContainerPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtContainerPeer.java new file mode 100644 index 000000000..ee2873730 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtContainerPeer.java @@ -0,0 +1,112 @@ +/* QtContainerPeer.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Component; +import java.awt.Insets; +import java.awt.peer.ContainerPeer; + +public class QtContainerPeer extends QtComponentPeer implements ContainerPeer +{ + public QtContainerPeer( QtToolkit kit, Component owner ) + { + super( kit, owner ); + } + + protected void init() + { + } + + protected void setup() + { + super.setup(); + } + + // ************ Public methods ********************* + public void beginLayout() + { + // FIXME + } + + public void beginValidate() + { + } + + public void endLayout() + { + QtUpdate(); + } + + public void endValidate() + { + } + + public Insets getInsets() + { + return new Insets(0, 0, 0, 0); + } + + public Insets insets() + { + return getInsets(); + } + + public boolean isPaintPending() + { + // FIXME etc. + return false; + } + + public boolean isRestackSupported() + { + // TODO Auto-generated method stub + return false; + } + + public void cancelPendingPaint(int x, int y, int width, int height) + { + // TODO Auto-generated method stub + + } + + public void restack() + { + // TODO Auto-generated method stub + + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtDialogPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtDialogPeer.java new file mode 100644 index 000000000..2f2c25550 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtDialogPeer.java @@ -0,0 +1,73 @@ +/* QtDialogPeer.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Dialog; +import java.awt.peer.DialogPeer; + +public class QtDialogPeer extends QtWindowPeer implements DialogPeer +{ + public QtDialogPeer( QtToolkit kit, Dialog owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setTitle( ((Dialog)owner).getTitle() ); + setResizable( ((Dialog)owner).isResizable() ); + setModal( ((Dialog)owner).isModal() ); + } + + native void setModal(boolean modal); + + private native void setBoundsNative(int x, int y, int width, int height, boolean fixed); + + // ************ Public methods ********************* + + public native void setResizable (boolean resizeable); + + public void setBounds(int x, int y, int width, int height) + { + setBoundsNative(x, y, width, height, + !((Dialog)owner).isResizable()); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtEmbeddedWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtEmbeddedWindowPeer.java new file mode 100644 index 000000000..de76cd17f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtEmbeddedWindowPeer.java @@ -0,0 +1,64 @@ +/* QtEmbeddedWindowPeer.java -- embedded window peer + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Component; +import gnu.java.awt.peer.EmbeddedWindowPeer; + +/** + * Embedded window peer for applets. + * FIXME: EmbeddedWindowPeer and this class should extend Window, NOT Frame. + */ +public class QtEmbeddedWindowPeer extends QtFramePeer implements EmbeddedWindowPeer +{ + public QtEmbeddedWindowPeer( QtToolkit kit, Component owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + } + + // ************ Public methods ********************* + + public native void embed( long handle ); +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtFileDialogPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtFileDialogPeer.java new file mode 100644 index 000000000..06943d955 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtFileDialogPeer.java @@ -0,0 +1,83 @@ +/* QtFileDialogPeer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.FileDialog; +import java.io.FilenameFilter; +import java.awt.peer.FileDialogPeer; + +public class QtFileDialogPeer extends QtDialogPeer implements FileDialogPeer +{ + public QtFileDialogPeer( QtToolkit kit, FileDialog owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setMode( ((FileDialog)owner).getMode() ); + } + + /** + * Sets load or save mode + */ + private native void setMode(int mode); + + private void fileDialogDone(String path, String filename) + { + } + + // ************ Public methods ********************* + public void setFile (String file) + { + // FIXME + } + + public void setDirectory (String dir) + { + // FIXME + } + + public void setFilenameFilter (FilenameFilter ff) + { + // FIXME + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtFontMetrics.java b/libjava/classpath/gnu/java/awt/peer/qt/QtFontMetrics.java new file mode 100644 index 000000000..1998339dc --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtFontMetrics.java @@ -0,0 +1,125 @@ +/* QtFontMetrics.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.geom.Rectangle2D; + +public class QtFontMetrics extends FontMetrics +{ + + private long nativeObject; + private QtFontPeer peer; + + public QtFontMetrics( Font f ) + { + super( f ); + if(f.getPeer() == null || !(f.getPeer() instanceof QtFontPeer)) + throw new IllegalArgumentException("Invalid Font object."); + peer = (QtFontPeer) f.getPeer(); + init( peer ); + } + + public QtFontMetrics( Font f, Graphics g ) + { + super( f ); + if(f.getPeer() == null || !(f.getPeer() instanceof QtFontPeer)) + throw new IllegalArgumentException("Invalid Font object."); + if( !(g instanceof QtGraphics) ) + throw new IllegalArgumentException("Invalid graphics object."); + peer = (QtFontPeer) f.getPeer(); + initGraphics(peer, (QtGraphics)g ); + } + + QtFontMetrics( QtFontPeer f, Graphics g ) + { + super( null ); + if( !(g instanceof QtGraphics) ) + throw new IllegalArgumentException("Invalid graphics object."); + peer = f; + initGraphics(peer, (QtGraphics)g ); + } + + public QtFontMetrics( QtFontPeer fp ) + { + super( (Font)null ); + peer = fp; + init( peer ); + } + + private native void init(QtFontPeer fp); + + private native void initGraphics(QtFontPeer fp, QtGraphics g); + + private native void dispose(); + + native Rectangle2D getStringBounds(String s); + + // ****************** Package private *************************** + + native boolean canDisplay( int c ); + + // ****************** Public methods **************************** + + public native int getAscent(); + + public native int getDescent(); + + public native int getHeight(); + + public native int getLeading(); + + public native int getMaxAdvance(); + + public native int charWidth(char c); + + public int charsWidth(char[] chars, int off, int len) + { + return stringWidth( new String(chars, off, len) ); + } + + public native int stringWidth(String str); + + public Rectangle2D getStringBounds(String str, Graphics context) + { + QtFontMetrics fm = new QtFontMetrics(peer, context); + return fm.getStringBounds( str ); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtFontPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtFontPeer.java new file mode 100644 index 000000000..03ed1d2df --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtFontPeer.java @@ -0,0 +1,197 @@ +/* QtFontPeer.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.geom.Rectangle2D; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineMetrics; +import java.text.CharacterIterator; +import java.util.Locale; +import java.util.Map; + +import gnu.java.awt.peer.ClasspathFontPeer; + +public class QtFontPeer extends ClasspathFontPeer +{ + // Pointer to native QFont structure. + private long nativeObject; + private QtFontMetrics metrics; + + + public QtFontPeer (String name, int style) + { + this(name, style, 12); + } + + public QtFontPeer (String name, int style, int size) + { + super(name, style, size); + init(); + } + + public QtFontPeer (String name, Map attributes) + { + super(name, attributes); + init(); + } + + public void init() + { + if(this.familyName == null) + throw new IllegalArgumentException("null family name"); + if(this.familyName.equals("Helvetica")) + this.familyName = "sans serif"; + if(this.familyName.equals("Dialog")) + this.familyName = "sans serif"; + create(this.familyName, this.style, (int)this.size); + metrics = new QtFontMetrics(this); + } + + /** + * Creates the QFont object. + */ + private native void create(String name, int style, int size); + + /** + * Destroys the QFont. + */ + public native void dispose(); + + + // ****************** ClasspathFontPeer Methods. + + public boolean canDisplay (Font font, int c) + { + return metrics.canDisplay( c ); + } + + public int canDisplayUpTo (Font font, CharacterIterator i, + int start, int limit) + { + int index = start; + char c = i.setIndex( index ); + while( index <= limit ) + { + if(!canDisplay(font, c)) + return index; + index++; + c = i.next(); + } + return -1; + } + + public String getSubFamilyName (Font font, Locale locale) + { + throw new UnsupportedOperationException(); + } + + public String getPostScriptName (Font font) + { + throw new UnsupportedOperationException(); + } + + public int getNumGlyphs (Font font) + { + throw new UnsupportedOperationException(); + } + + public int getMissingGlyphCode (Font font) + { + throw new UnsupportedOperationException(); + } + + public byte getBaselineFor (Font font, char c) + { + throw new UnsupportedOperationException(); + } + + public String getGlyphName (Font font, int glyphIndex) + { + throw new UnsupportedOperationException(); + } + + public GlyphVector createGlyphVector (Font font, + FontRenderContext frc, + CharacterIterator ci) + { + throw new UnsupportedOperationException(); + } + + public GlyphVector createGlyphVector (Font font, + FontRenderContext ctx, + int[] glyphCodes) + { + throw new UnsupportedOperationException(); + } + + public GlyphVector layoutGlyphVector (Font font, + FontRenderContext frc, + char[] chars, int start, + int limit, int flags) + { + throw new UnsupportedOperationException(); + } + + public FontMetrics getFontMetrics (Font font) + { + return new QtFontMetrics( this ); + } + + public boolean hasUniformLineMetrics (Font font) + { + throw new UnsupportedOperationException(); + } + + public LineMetrics getLineMetrics (Font font, + CharacterIterator ci, + int begin, int limit, + FontRenderContext rc) + { + throw new UnsupportedOperationException(); + } + + public Rectangle2D getMaxCharBounds (Font font, + FontRenderContext rc) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtFramePeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtFramePeer.java new file mode 100644 index 000000000..d5162106f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtFramePeer.java @@ -0,0 +1,164 @@ +/* QtFramePeer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Component; +import java.awt.Frame; +import java.awt.Image; +import java.awt.Insets; +import java.awt.MenuBar; +import java.awt.Rectangle; +import java.awt.peer.FramePeer; + +public class QtFramePeer extends QtWindowPeer implements FramePeer +{ + private int theState; // FIXME + + long frameObject; + + public QtFramePeer( QtToolkit kit, Component owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setTitle( ((Frame)owner).getTitle() ); + if( ((Frame)owner).getMenuBar() != null ) + setMenuBar( ((Frame)owner).getMenuBar() ); + } + + private native void setIcon(QtImage image); + + private native void setMaximizedBounds(int w, int h); + + private native void setMenu(QtMenuBarPeer mb); + + private native int menuBarHeight(); + + // ************ Public methods ********************* + + public void destroy() + { + dispose(); + } + + public int getState() + { + // FIXME + return theState; + } + + public Insets getInsets() + { + int mbHeight = ( ((Frame)owner).getMenuBar() != null ) ? + menuBarHeight() : 0; + return new Insets(mbHeight, 0, 0, 0); + } + + public void setIconImage(Image im) + { + if (im instanceof QtImage) + setIcon( (QtImage)im ); + else + setIcon( new QtImage( im.getSource() ) ); + } + + public void setMaximizedBounds(Rectangle rect) + { + // FIXME + } + + public void setMenuBar(MenuBar mb) + { + if( mb != null ) + { + QtMenuBarPeer mbpeer = (QtMenuBarPeer)mb.getPeer(); + if( mbpeer == null ) + { + mb.addNotify(); + mbpeer = (QtMenuBarPeer)mb.getPeer(); + if( mbpeer == null ) + throw new IllegalStateException("No menu bar peer."); + } + mbpeer.addMenus(); + setMenu( mbpeer ); + } + else + setMenu( null ); + } + + public void setResizable(boolean resizeable) + { + // FIXME + } + + public void setState(int s) + { + theState = s; + // FIXME + } + + public void setBoundsPrivate(int x, int y, int width, int height) + { + // TODO Auto-generated method stub + + } + + public void updateAlwaysOnTop() + { + // TODO Auto-generated method stub + + } + + public boolean requestWindowFocus() + { + // TODO Auto-generated method stub + return false; + } + + public Rectangle getBoundsPrivate() + { + // TODO: Implement this properly. + throw new InternalError("Not yet implemented"); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtGraphics.java b/libjava/classpath/gnu/java/awt/peer/qt/QtGraphics.java new file mode 100644 index 000000000..f68cc0dbd --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtGraphics.java @@ -0,0 +1,714 @@ +/* QtGraphics.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.AlphaComposite; +import java.awt.AWTPermission; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.GradientPaint; +import java.awt.GraphicsConfiguration; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.RenderingHints; +import java.awt.Rectangle; +import java.awt.Paint; +import java.awt.Polygon; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Line2D; +import java.awt.geom.Rectangle2D; +import java.awt.geom.RoundRectangle2D; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.ImageObserver; +import java.awt.image.RenderedImage; +import java.awt.image.renderable.RenderableImage; + +import java.text.AttributedCharacterIterator; +import java.text.CharacterIterator; +import java.util.Map; + +/** + * QtGraphics is an abstract implementation of Graphics2D over a QPainter + * object. This is to be subclassed for different drawing contexts, + * which may have different requirements. + */ +public abstract class QtGraphics extends Graphics2D +{ + /** + * Native QPainter pointer. + */ + protected long nativeObject; + + private static final AffineTransform identity = new AffineTransform(); + + // Graphics state + protected Font font; // Current font. + protected Color color, bgcolor; // Current color and background color. + protected Shape clip; // Current clipping area. + protected Shape initialClip; // Initial clip bounds + protected AffineTransform xform; // Current transform + protected Stroke currentStroke; // the current stroke + protected boolean nativeStroking; // whether we're using Qt's stroking or not + protected Composite composite; // current composite operator + protected double currentAlpha; // current alpha + protected Paint currentPaint; // current paint + protected RenderingHints renderingHints; // the rendering hints. + + /** + * Owner Graphics, used by subcontext created by create() + * to avoid GC of the original context. + */ + Graphics parent; + + /** + * Do-nothing constructor. + */ + QtGraphics() + { + } + + /** + * Copying constructor - used by copy() and subclasses. + */ + QtGraphics(QtGraphics parent) + { + cloneNativeContext( parent ); + setFont( parent.getFont() ); + setAlpha( parent.currentAlpha ); + setBackground( parent.getBackground() ); + setColor( parent.getColor() ); + setClip( (initialClip = parent.getClip()) ); + setTransform( parent.getTransform() ); + setStroke( parent.getStroke() ); + setComposite( parent.getComposite() ); + setPaint( parent.getPaint() ); + setRenderingHints( parent.getRenderingHints() ); + } + + /** + * Set up some generic defaults. + */ + protected void setup() + { + font = new Font ("Dialog", Font.PLAIN, 12); + setTransform( identity ); + setStroke( new BasicStroke() ); + renderingHints = new RenderingHints( null ); + } + + public synchronized native void delete(); + + public void dispose() + { + } + + // ********************** etc ******************************* + + private void resetClip() + { + AffineTransform current = getTransform(); + setTransform( identity ); + setClip( initialClip ); + setTransform( current ); + } + + protected native void initImage(QtImage image); + protected native void initVolatileImage(QtVolatileImage image); + + // Creates a new native QPainter object on the same context. + private native void cloneNativeContext( QtGraphics parent ); + private native void setColor(int r, int g, int b, int a); + private native void drawNative( QPainterPath p ); + private native void fillNative( QPainterPath p ); + private native void setClipNative( QPainterPath p ); + private native void setClipRectNative( int x, int y, int w, int h ); + private native void intersectClipNative( QPainterPath p ); + private native void intersectClipRectNative( int x, int y, int w, int h ); + private native void setQtTransform(QMatrix m); + private native void setNativeStroke(QPen p); + private native void setNativeComposite(int alphaMode); + private native void drawStringNative(String string, double x, double y); + private native void setLinearGradient(int r1, int g1, int b1, + int r2, int g2, int b2, + double x1, double y1, + double x2, double y2, boolean cyclic); + private native void setAlphaNative(double alpha); + private native void setFontNative(QtFontPeer font); + private native QPainterPath getClipNative(); + + void setAlpha(double alpha) + { + currentAlpha = alpha; + setAlphaNative(currentAlpha); + } + + // ************ Public methods ********************* + + /** + * Context-sensitive methods are declared abstract. + */ + public abstract Graphics create(); + + public abstract void copyArea(int x, int y, int width, int height, + int dx, int dy); + + public abstract GraphicsConfiguration getDeviceConfiguration(); + + + public Color getColor() + { + return new Color(color.getRed(), color.getGreen(), color.getBlue()); + } + + public void setColor(Color c) + { + if( c == null ) + c = Color.white; + this.color = c; + int alpha = (int)(c.getAlpha() * currentAlpha); + setColor(c.getRed(), c.getGreen(), c.getBlue(), alpha); + } + + public void setBackground(Color color) + { + bgcolor = new Color(color.getRed(), color.getGreen(), color.getBlue()); + } + + public Color getBackground() + { + return new Color(bgcolor.getRed(), bgcolor.getGreen(), bgcolor.getBlue()); + } + + public void setPaintMode() + { + } + + public void setXORMode(Color color) + { + // FIXME + } + + public boolean hit(Rectangle rect, Shape s, boolean onStroke) + { + if( onStroke ) + { + Shape stroked = currentStroke.createStrokedShape( s ); + return stroked.intersects( (double)rect.x, (double)rect.y, + (double)rect.width, (double)rect.height ); + } + return s.intersects( (double)rect.x, (double)rect.y, + (double)rect.width, (double)rect.height ); + } + + // ******************* Font *********************** + public Font getFont() + { + return font; + } + + public void setFont(Font font) + { + if( font == null ) + return; + this.font = font; + if(font.getPeer() != null && font.getPeer() instanceof QtFontPeer) + setFontNative( (QtFontPeer)font.getPeer() ); + } + + public FontMetrics getFontMetrics(Font font) + { + return new QtFontMetrics(font, this); + } + + // ***************** Clipping ********************* + + /** + * Intersects the current clip with the shape + */ + public void clip(Shape s) + { + intersectClipNative( new QPainterPath( s ) ); + } + + public void clipRect(int x, int y, int width, int height) + { + intersectClipRectNative( x, y, width, height ); + } + + public void setClip(int x, int y, int width, int height) + { + setClipRectNative( x, y, width, height ); + } + + public Shape getClip() + { + return getClipNative().getPath(); + } + + public native Rectangle getClipBounds(); + + /** + * Sets the clip + */ + public void setClip(Shape clip) + { + if (clip == null) + resetClip(); + else + setClipNative(new QPainterPath( clip )); + } + + // ***************** Drawing primitives ********************* + + public void draw(Shape s) + { + if( nativeStroking ) + drawNative( new QPainterPath(s) ); + else + fillNative( new QPainterPath( currentStroke.createStrokedShape( s ) ) ); + } + + public void fill(Shape s) + { + fillNative( new QPainterPath(s) ); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + if( nativeStroking ) + drawNative( new QPainterPath((double)x1, (double)y1, (double)x2, (double)y2, true) ); + else + draw( new Line2D.Double((double)x1, (double)y1, (double)x2, (double)y2) ); + } + + public void drawRect(int x, int y, int width, int height) + { + if( nativeStroking ) + drawNative( new QPainterPath((double)x, (double)y, + (double)width, (double)height) ); + else + fillNative( new QPainterPath + ( currentStroke.createStrokedShape + (new Rectangle2D.Double + ((double)x, (double)y, + (double)width, (double)height) ) ) ); + } + + public void fillRect(int x, int y, int width, int height) + { + fillNative( new QPainterPath( x, y, width, height ) ); + } + + public void clearRect(int x, int y, int width, int height) + { + Color c = color; + setColor( bgcolor ); // FIXME + fillRect( x, y, width, height ); + setColor( c ); + } + + public void drawRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) + { + draw( new RoundRectangle2D.Double(x, y, width, height, + arcWidth, arcHeight) ); + } + + public void fillRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) + { + fill( new RoundRectangle2D.Double(x, y, width, height, + arcWidth, arcHeight) ); + } + + public void drawOval(int x, int y, int width, int height) + { + draw( new Ellipse2D.Double((double)x, (double)y, + (double)width, (double)height) ); + } + + public void fillOval(int x, int y, int width, int height) + { + fill( new Ellipse2D.Double(x, y, width, height) ); + } + + public void drawArc(int x, int y, int width, int height, + int arcStart, int arcAngle) + { + draw( new Arc2D.Double(x, y, width, height, arcStart, arcAngle, + Arc2D.OPEN) ); + } + + public void fillArc(int x, int y, int width, int height, + int arcStart, int arcAngle) + { + fill( new Arc2D.Double(x, y, width, height, arcStart, arcAngle, + Arc2D.CHORD) ); + } + + public void drawPolyline(int xPoints[], int yPoints[], int npoints) + { + for( int i = 0; i < npoints - 1; i++) + drawLine(xPoints[i], yPoints[i], xPoints[i + 1], yPoints[i + 1]); + } + + public void drawPolygon(int xPoints[], int yPoints[], int npoints) + { + draw( new Polygon(xPoints, yPoints, npoints) ); + } + + public void fillPolygon(int xPoints[], int yPoints[], int npoints) + { + fill( new Polygon(xPoints, yPoints, npoints) ); + } + + public native void fill3DRect(int x, int y, int width, int height, boolean raised); + + public native void draw3DRect(int x, int y, int width, int height, boolean raised); + + // *********************** Text rendering ************************* + + public void drawString(String string, int x, int y) + { + drawStringNative(string, (double)x, (double)y); + } + + public void drawString(String string, float x, float y) + { + drawStringNative(string, (double)x, (double)y); + } + + public void drawString (AttributedCharacterIterator ci, int x, int y) + { + // FIXME - to something more correct ? + String s = ""; + for(char c = ci.first(); c != CharacterIterator.DONE; c = ci.next()) + s += c; + drawString(s, x, y); + } + + public void drawString(AttributedCharacterIterator ci, + float x, float y) + { + // FIXME - to something more correct ? + String s = ""; + for(char c = ci.first(); c != CharacterIterator.DONE; c = ci.next()) + s += c; + drawString(s, x, y); + } + + public void drawGlyphVector(GlyphVector v, float x, float y) + { + throw new RuntimeException("Not implemented"); + } + + // ******************* Image drawing ****************************** + public boolean drawImage(Image image, + AffineTransform Tx, + ImageObserver obs) + { + if (image instanceof QtImage) + return ((QtImage)image).drawImage(this, new QMatrix( Tx ), obs); + + return (new QtImage(image.getSource())).drawImage(this, + new QMatrix( Tx ), + obs); + } + + public boolean drawImage(Image image, int x, int y, Color bgcolor, + ImageObserver observer) + { + if (image instanceof QtImage) + return ((QtImage)image).drawImage (this, x, y, bgcolor, observer); + return (new QtImage(image.getSource())).drawImage (this, x, y, + bgcolor, observer); + } + + public boolean drawImage(Image image, + int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer) + { + if (image instanceof QtImage) + return ((QtImage)image).drawImage(this, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, bgcolor, observer); + + return (new QtImage(image.getSource())).drawImage(this, dx1, dy1, + dx2, dy2, + sx1, sy1, sx2, sy2, + bgcolor, observer); + } + + public boolean drawImage(Image image, int x, int y, + int width, int height, Color bgcolor, + ImageObserver observer) + { + if (image instanceof QtImage) + return ((QtImage)image).drawImage (this, x, y, width, height, + bgcolor, observer); + return (new QtImage(image.getSource())).drawImage (this, x, y, + width, height, + bgcolor, observer); + } + + public boolean drawImage(Image image, int x, int y, int width, int height, + ImageObserver observer) + { + return drawImage(image, x, y, width, height, null, observer); + } + + public boolean drawImage(Image image, int x, int y, ImageObserver observer) + { + return drawImage(image, x, y, null, observer); + } + + public boolean drawImage(Image image, int dx1, int dy1, int dx2, int dy2, int sx1, int sy1, int sx2, int sy2, ImageObserver observer) + { + return drawImage(image, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, null, observer); + } + + // *********************** Transform methods ************************* + public AffineTransform getTransform() + { + return new AffineTransform( xform ); + } + + public void setTransform(AffineTransform Tx) + { + xform = new AffineTransform( Tx ); + setQtTransform( new QMatrix( xform ) ); + } + + public void rotate(double theta) + { + xform.rotate( theta ); + setQtTransform( new QMatrix( xform ) ); + } + + public void rotate(double theta, double x, double y) + { + xform.rotate(theta, x, y); + setQtTransform( new QMatrix( xform ) ); + } + + public void scale(double sx, double sy) + { + xform.scale(sx, sy); + setQtTransform( new QMatrix( xform ) ); + } + + public void shear(double shx, double shy) + { + xform.shear(shx, shy); + setQtTransform( new QMatrix( xform ) ); + } + + public void transform(AffineTransform Tx) + { + xform.concatenate( Tx ); + setQtTransform( new QMatrix( xform ) ); + } + + public void translate(double tx, double ty) + { + xform.translate( tx, ty ); + setQtTransform( new QMatrix( xform ) ); + } + + public void translate(int x, int y) + { + translate((double)x, (double)y); + } + + // *************** Stroking, Filling, Compositing ***************** + public void setStroke(Stroke s) + { + try // ..to convert the stroke into a native one. + { + QPen pen = new QPen( s ); + nativeStroking = true; + setNativeStroke( pen ); + setColor( color ); + } + catch (IllegalArgumentException e) + { + nativeStroking = false; + } + currentStroke = s; + } + + public Stroke getStroke() + { // FIXME: return copy? + return currentStroke; + } + + public void setComposite(Composite comp) + { + if( comp == null) + { + setNativeComposite( AlphaComposite.SRC_OVER ); + return; + } + + if( comp instanceof AlphaComposite ) + { + if( ((AlphaComposite)comp).getRule() != AlphaComposite.XOR ) + setAlpha( ((AlphaComposite)comp).getAlpha() ); + setNativeComposite( ((AlphaComposite)comp).getRule() ); + composite = comp; + } + else + { + // FIXME: this check is only required "if this Graphics2D + // context is drawing to a Component on the display screen". + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new AWTPermission("readDisplayPixels")); + + throw new UnsupportedOperationException("We don't support custom"+ + " composites yet."); + } + } + + public Composite getComposite() + { + return composite; + } + + public void setPaint(Paint p) + { + if( p == null ) + return; + + // FIXME + currentPaint = p; + if( p instanceof GradientPaint ) + { + GradientPaint lg = (GradientPaint)p; + setLinearGradient(lg.getColor1().getRed(), lg.getColor1().getGreen(), + lg.getColor1().getBlue(), lg.getColor2().getRed(), + lg.getColor2().getGreen(), lg.getColor2().getBlue(), + lg.getPoint1().getX(), lg.getPoint1().getY(), + lg.getPoint2().getX(), lg.getPoint2().getY(), + lg.isCyclic() ); + return; + } + if( p instanceof Color ) + { + setColor((Color) p); + return; + } + throw new UnsupportedOperationException("We don't support custom"+ + " paints yet."); + } + + public Paint getPaint() + { + // FIXME + return currentPaint; + } + + // ********************** Rendering Hints ************************* + + public void addRenderingHints(Map hints) + { + renderingHints.putAll( hints ); + } + + public Object getRenderingHint(RenderingHints.Key hintKey) + { + return renderingHints.get( hintKey ); + } + + public RenderingHints getRenderingHints() + { + return (RenderingHints) renderingHints.clone(); + } + + public void setRenderingHints(Map hints) + { + renderingHints = new RenderingHints( null ); + renderingHints.putAll(hints); + updateRenderingHints(); + } + + public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) + { + renderingHints.put( hintKey, hintValue ); + updateRenderingHints(); + } + + private void updateRenderingHints() + { + // FIXME - update native settings. + } + + ////////////////////////////// unimplemented ///////////////////// + + public FontRenderContext getFontRenderContext() + { + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void drawRenderableImage(RenderableImage image, AffineTransform xform) + { + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void drawRenderedImage(RenderedImage image, AffineTransform xform) + { + throw new UnsupportedOperationException("Not implemented yet"); + } + + public void drawImage(BufferedImage image, BufferedImageOp op, int x, int y) + { + throw new UnsupportedOperationException("Not implemented yet"); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/peer/qt/QtGraphicsEnvironment.java new file mode 100644 index 000000000..dec4db2c8 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtGraphicsEnvironment.java @@ -0,0 +1,105 @@ +/* QtGraphicsEnvironment.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.image.BufferedImage; +import java.util.Locale; + +public class QtGraphicsEnvironment extends GraphicsEnvironment +{ + QtToolkit toolkit; + GraphicsDevice[] screens; + + public QtGraphicsEnvironment (QtToolkit tk) + { + super(); + toolkit = tk; + // Get the number of screens from Qt. + int n = toolkit.numScreens(); + + /** + * Create the screen device objects + */ + screens = new GraphicsDevice[ n ]; + for(int i = 0; i < n; i++) + screens[ i ] = new QtScreenDevice( i ); + } + + public Font[] getAllFonts () + { + String[] fonts = getAvailableFontFamilyNames(); + Font[] fontObjs = new Font[fonts.length]; + for( int i = 0; i < fonts.length; i++) + fontObjs[i] = new Font(fonts[i], Font.PLAIN, 12); + return fontObjs; + } + + public String[] getAvailableFontFamilyNames() + { + return toolkit.getFontList(); + } + + public String[] getAvailableFontFamilyNames(Locale l) + { + return getAvailableFontFamilyNames(); + } + + public GraphicsDevice getDefaultScreenDevice () + { + return screens[ toolkit.defaultScreen() ]; + } + + public Graphics2D createGraphics (BufferedImage image) + { + return (Graphics2D)image.getGraphics(); + } + + public GraphicsDevice[] getScreenDevices() + { + return screens; + } + + public QtToolkit getToolkit() + { + return toolkit; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtImage.java b/libjava/classpath/gnu/java/awt/peer/qt/QtImage.java new file mode 100644 index 000000000..b7e50ea25 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtImage.java @@ -0,0 +1,641 @@ +/* QtImage.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Graphics; +import java.awt.Color; +import java.awt.Image; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.MemoryImageSource; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.io.File; +import java.io.IOException; +import java.io.ByteArrayOutputStream; +import java.io.BufferedInputStream; +import java.net.URL; +import java.util.Hashtable; +import java.util.WeakHashMap; +import java.util.Vector; + +/** + * QtImage - wraps a QImage + * + */ +public class QtImage extends Image +{ + int width = -1, height = -1; + + /** + * Properties. + */ + Hashtable props; + + /** + * Loaded or not flag, for asynchronous compatibility. + */ + boolean isLoaded; + + /** + * Pointer to the QImage + */ + long nativeObject; + + /** + * Observer queue. + */ + Vector observers; + + /** + * Error flag for loading. + */ + boolean errorLoading; + + /** + * Original source, if created from an ImageProducer. + */ + ImageProducer source; + + /* + * The 32-bit AARRGGBB format the uses. + */ + static ColorModel nativeModel = new DirectColorModel(32, + 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000); + /** + * HashMap of Graphics objects painting on this Image. + */ + WeakHashMap painters; + + /** + * Flags if this image is to be destroyed. + */ + boolean killFlag; + + /** + * Clears the image to RGBA 0 + */ + public native void clear(); + + /** + * Returns a copy of the pixel data as a java array. + */ + private native int[] getPixels(); + + /** + * Sets the pixel data from a java array. + */ + private native void setPixels(int[] pixels); + + /** + * Loads an image + */ + private native boolean loadImage(String name); + + /** + * Loads an image from data. + */ + private native boolean loadImageFromData(byte[] data); + + /** + * Allocates a QImage + */ + private native void createImage(); + + /** + * Frees the above. + */ + private synchronized native void freeImage(); + + /** + * Sets the image to scaled copy of src image. hints are rendering hints. + */ + private native void createScaledImage(QtImage src, int hints); + + /** + * Draws the image optionally composited. + */ + native void drawPixels (QtGraphics gc, + int bg_red, int bg_green, int bg_blue, + int x, int y, + boolean composite); + /** + * Draws the image, optionally scaled and composited. + */ + private native void drawPixelsScaled (QtGraphics gc, + int bg_red, int bg_green, int bg_blue, + int x, int y, int width, int height, + boolean composite); + + /** + * Draws the image transformed. + */ + private native void drawPixelsTransformed (QtGraphics gc, QMatrix transform); + + /** + * Draws the image scaled flipped and optionally composited. + */ + native void drawPixelsScaledFlipped (QtGraphics gc, + int bg_red, int bg_green, + int bg_blue, + boolean flipX, boolean flipY, + int srcX, int srcY, + int srcWidth, int srcHeight, + int dstX, int dstY, + int dstWidth, int dstHeight, + boolean composite); + + /** + * Creates the image from an ImageProducer. May result in an error image. + */ + public QtImage (ImageProducer producer) + { + killFlag = false; + isLoaded = false; + observers = new Vector(); + source = producer; + errorLoading = false; + if( producer != null ) + source.startProduction(new QtImageConsumer(this, source)); + } + + /** + * Creates the image from a URL. May result in an error image. + */ + public QtImage (URL url) + { + killFlag = false; + isLoaded = false; + observers = new Vector(); + errorLoading = false; + if( url == null) + return; + ByteArrayOutputStream baos = new ByteArrayOutputStream( 5000 ); + try + { + BufferedInputStream bis = new BufferedInputStream(url.openStream()); + + byte[] buf = new byte[5000]; + int n = 0; + + while ( (n = bis.read( buf )) != -1 ) + baos.write(buf, 0, n); + bis.close(); + } + catch(IOException e) + { + throw new IllegalArgumentException("Couldn't load image."); + } + if ( loadImageFromData( baos.toByteArray() ) != true ) + throw new IllegalArgumentException("Couldn't load image."); + + isLoaded = true; + observers = null; + props = new Hashtable(); + } + + /** + * Constructs a QtImage by loading a given file. + * + * @throws IllegalArgumentException if the image could not be loaded. + */ + public QtImage (String filename) + { + killFlag = false; + File f = new File(filename); + observers = null; + props = new Hashtable(); + try + { + String fn = f.getCanonicalPath(); + if (loadImage( fn ) != true) + { + errorLoading = true; + isLoaded = false; + return; + } + } + catch(IOException e) + { + errorLoading = true; + isLoaded = false; + return; + } + errorLoading = false; + isLoaded = true; + } + + /** + * Constructs a QtImage from a byte array of an image file. + * + * @throws IllegalArgumentException if the image could not be loaded. + */ + public QtImage (byte[] data) + { + if (loadImageFromData(data) != true) + throw new IllegalArgumentException("Couldn't load image."); + + killFlag = false; + isLoaded = true; + observers = null; + errorLoading = false; + props = new Hashtable(); + } + + /** + * Constructs an empty QtImage. + */ + public QtImage (int width, int height) + { + this.width = width; + this.height = height; + props = new Hashtable(); + isLoaded = true; + killFlag = false; + observers = null; + errorLoading = false; + createImage(); + clear(); + } + + /** + * Constructs a scaled version of the src bitmap, using Qt + */ + private QtImage (QtImage src, int width, int height, int hints) + { + this.width = width; + this.height = height; + props = new Hashtable(); + isLoaded = true; + killFlag = false; + observers = null; + errorLoading = false; + + createScaledImage(src, hints); + } + + /** + * Callback from the image consumer. + */ + public void setImage(int width, int height, + int[] pixels, Hashtable properties) + { + this.width = width; + this.height = height; + props = (properties != null) ? properties : new Hashtable(); + + if (width <= 0 || height <= 0 || pixels == null) + { + errorLoading = true; + return; + } + + isLoaded = true; + deliver(); + createImage(); + setPixels(pixels); + } + + // java.awt.Image methods //////////////////////////////////////////////// + + public int getWidth (ImageObserver observer) + { + if (addObserver(observer)) + return -1; + + return width; + } + + public int getHeight (ImageObserver observer) + { + if (addObserver(observer)) + return -1; + + return height; + } + + public Object getProperty (String name, ImageObserver observer) + { + if (addObserver(observer)) + return UndefinedProperty; + + Object value = props.get (name); + return (value == null) ? UndefinedProperty : value; + } + + /** + * Returns the source of this image. + */ + public ImageProducer getSource () + { + if (!isLoaded) + return null; + return new MemoryImageSource(width, height, nativeModel, getPixels(), + 0, width); + } + + void putPainter(QtImageGraphics g) + { + if( painters == null ) + painters = new WeakHashMap(); + painters.put( g, "dummy" ); + } + + void removePainter(QtImageGraphics g) + { + painters.remove( g ); + if( killFlag && painters.isEmpty() ) + freeImage(); + } + + /** + * Creates a Graphics context for this image. + */ + public Graphics getGraphics () + { + if (!isLoaded || killFlag) + return null; + + return new QtImageGraphics(this); + } + + /** + * Creates a Graphics context for this image. + */ + Graphics getDirectGraphics(QtComponentPeer peer) + { + if (!isLoaded) + return null; + + return new QtImageDirectGraphics(this, peer); + } + + /** + * Returns a scaled instance of this image. + */ + public Image getScaledInstance(int width, + int height, + int hints) + { + if (width <= 0 || height <= 0) + throw new IllegalArgumentException("Width and height of scaled bitmap"+ + "must be >= 0"); + + return new QtImage(this, width, height, hints); + } + + /** + * If the image is loaded and comes from an ImageProducer, + * regenerate the image from there. + * + * I have no idea if this is ever actually used. Since QtImage can't be + * instantiated directly, how is the user to know if it was created from + * an ImageProducer or not? + */ + public synchronized void flush () + { + if (isLoaded && source != null) + { + observers = new Vector(); + isLoaded = false; + freeImage(); + source.startProduction(new QtImageConsumer(this, source)); + } + } + + public void finalize() + { + dispose(); + } + + public void dispose() + { + if (isLoaded) + { + if( painters == null || painters.isEmpty() ) + freeImage(); + else + killFlag = true; // can't destroy image yet. + // Do so when all painters are gone. + } + } + + /** + * Returns the image status, used by QtToolkit + */ + public int checkImage (ImageObserver observer) + { + if (addObserver(observer)) + { + if (errorLoading == true) + return ImageObserver.ERROR; + else + return 0; + } + + return ImageObserver.ALLBITS | ImageObserver.WIDTH | ImageObserver.HEIGHT; + } + + // Drawing methods //////////////////////////////////////////////// + + /** + * Draws an image with eventual scaling/transforming. + */ + public boolean drawImage (QtGraphics g, QMatrix matrix, + ImageObserver observer) + { + if (addObserver(observer)) + return false; + + drawPixelsTransformed (g, matrix); + + return true; + } + + /** + * Draws an image to the QtGraphics context, at (x,y) with optional + * compositing with a background color. + */ + public boolean drawImage (QtGraphics g, int x, int y, + Color bgcolor, ImageObserver observer) + { + if (addObserver(observer)) + return false; + + if(bgcolor != null) + drawPixels(g, bgcolor.getRed (), bgcolor.getGreen (), + bgcolor.getBlue (), x, y, true); + else + drawPixels(g, 0, 0, 0, x, y, false); + + return true; + } + + /** + * Draws an image to the QtGraphics context, at (x,y) scaled to + * width and height, with optional compositing with a background color. + */ + public boolean drawImage (QtGraphics g, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + if (addObserver(observer)) + return false; + + if(bgcolor != null) + drawPixelsScaled(g, bgcolor.getRed (), bgcolor.getGreen (), + bgcolor.getBlue (), x, y, width, height, true); + else + drawPixelsScaled(g, 0, 0, 0, x, y, width, height, false); + + return true; + } + + /** + * Draws an image with eventual scaling/transforming. + */ + public boolean drawImage (QtGraphics g, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer) + { + if (addObserver(observer)) + return false; + + boolean flipX = (dx1 > dx2)^(sx1 > sx2); + boolean flipY = (dy1 > dy2)^(sy1 > sy2); + int dstWidth = Math.abs (dx2 - dx1); + int dstHeight = Math.abs (dy2 - dy1); + int srcWidth = Math.abs (sx2 - sx1); + int srcHeight = Math.abs (sy2 - sy1); + int srcX = (sx1 < sx2) ? sx1 : sx2; + int srcY = (sy1 < sy2) ? sy1 : sy2; + int dstX = (dx1 < dx2) ? dx1 : dx2; + int dstY = (dy1 < dy2) ? dy1 : dy2; + + // Clipping. This requires the dst to be scaled as well, + if (srcWidth > width) + { + dstWidth = (int)((double)dstWidth*((double)width/(double)srcWidth)); + srcWidth = width - srcX; + } + + if (srcHeight > height) + { + dstHeight = (int)((double)dstHeight*((double)height/(double)srcHeight)); + srcHeight = height - srcY; + } + + if (srcWidth + srcX > width) + { + dstWidth = (int)((double)dstWidth * (double)(width - srcX)/(double)srcWidth); + srcWidth = width - srcX; + } + + if (srcHeight + srcY > height) + { + dstHeight = (int)((double)dstHeight * (double)(width - srcY)/(double)srcHeight); + srcHeight = height - srcY; + } + + if ( srcWidth <= 0 || srcHeight <= 0 || dstWidth <= 0 || dstHeight <= 0) + return true; + + if(bgcolor != null) + drawPixelsScaledFlipped (g, bgcolor.getRed (), bgcolor.getGreen (), + bgcolor.getBlue (), + flipX, flipY, + srcX, srcY, + srcWidth, srcHeight, + dstX, dstY, + dstWidth, dstHeight, + true); + else + drawPixelsScaledFlipped (g, 0, 0, 0, flipX, flipY, + srcX, srcY, srcWidth, srcHeight, + dstX, dstY, dstWidth, dstHeight, + false); + return true; + } + + public native void copyArea(int x, int y, int width, int height, + int dx, int dy); + + // Private methods //////////////////////////////////////////////// + + /** + * Delivers notifications to all queued observers. + */ + private void deliver() + { + int flags = ImageObserver.HEIGHT | + ImageObserver.WIDTH | + ImageObserver.PROPERTIES | + ImageObserver.ALLBITS; + + if (observers != null) + for(int i=0; i < observers.size(); i++) + ((ImageObserver)observers.elementAt(i)). + imageUpdate(this, flags, 0, 0, width, height); + + observers = null; + } + + /** + * Adds an observer, if we need to. + * @return true if an observer was added. + */ + private boolean addObserver(ImageObserver observer) + { + if (!isLoaded) + { + if(observer != null) + if (!observers.contains (observer)) + observers.addElement (observer); + return true; + } + return false; + } + + public String toString() + { + return "QtImage [isLoaded="+isLoaded+", width="+width+", height="+height + +"]"; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtImageConsumer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtImageConsumer.java new file mode 100644 index 000000000..9883475f9 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtImageConsumer.java @@ -0,0 +1,147 @@ +/* QtImageConsumer.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.image.ColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageProducer; +import java.util.Hashtable; + +/** + * Helper class to QtImage. Sits and gathers pixels for a QtImage and then + * calls QtImage.setImage(). + * + * @author Sven de Marothy + */ +public class QtImageConsumer implements ImageConsumer +{ + private QtImage target; + private int width, height; + private Hashtable properties; + private int[] pixelCache = null; + private ImageProducer source; + + public QtImageConsumer(QtImage target, ImageProducer source) + { + this.target = target; + this.source = source; + } + + public synchronized void imageComplete (int status) + { + source.removeConsumer(this); + target.setImage(width, height, pixelCache, properties); + } + + public synchronized void setColorModel (ColorModel model) + { + // This method is to inform on what the most used color model + // in the image is, for optimization reasons. We ignore this + // information. + } + + public synchronized void setDimensions (int width, int height) + { + pixelCache = new int[width*height]; + + this.width = width; + this.height = height; + } + + public synchronized void setHints (int flags) + { + // This method informs us in which order the pixels are + // delivered, for progressive-loading support, etc. + // Since we wait until it's all loaded, we can ignore the hints. + } + + public synchronized void setPixels (int x, int y, int width, int height, + ColorModel cm, byte[] pixels, + int offset, int scansize) + { + setPixels (x, y, width, height, cm, convertPixels (pixels), offset, + scansize); + } + + public synchronized void setPixels (int x, int y, int width, int height, + ColorModel cm, int[] pixels, + int offset, int scansize) + { + if (pixelCache == null) + return; // Not sure this should ever happen. + + if (cm.equals(QtImage.nativeModel)) + for (int i = 0; i < height; i++) + System.arraycopy (pixels, offset + (i * scansize), + pixelCache, (y + i) * this.width + x, + width); + else + { + for (int i = 0; i < height; i++) + for (int j = 0; j < width; j++) + { + // get in AARRGGBB and convert to AABBGGRR + int pix = cm.getRGB(pixels[offset + (i * scansize) + x + j]); + byte b = (byte)(pix & 0xFF); + byte r = (byte)(((pix & 0x00FF0000) >> 16) & 0xFF); + pix &= 0xFF00FF00; + pix |= ((b & 0xFF) << 16); + pix |= (r & 0xFF); + pixelCache[(y + i) * this.width + x + j] = pix; + } + } + } + + /** + * This is an old method, no idea if it's correct. + */ + private int[] convertPixels (byte[] pixels) + { + int ret[] = new int[pixels.length]; + + for (int i = 0; i < pixels.length; i++) + ret[i] = pixels[i] & 0xFF; + + return ret; + } + + public synchronized void setProperties (Hashtable props) + { + this.properties = props; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtImageDirectGraphics.java b/libjava/classpath/gnu/java/awt/peer/qt/QtImageDirectGraphics.java new file mode 100644 index 000000000..daa174ad4 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtImageDirectGraphics.java @@ -0,0 +1,145 @@ +/* QtImageDirectGraphics.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Color; +import java.awt.Image; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.image.ImageObserver; + +/** + * A QtImagePainter that does an update after every drawing op. + */ +public class QtImageDirectGraphics extends QtImageGraphics +{ + private QtComponentPeer peer; + private boolean modified; + + public QtImageDirectGraphics(QtImage image, QtComponentPeer peer) + { + super( image ); + this.peer = peer; + modified = false; + } + + public QtImageDirectGraphics(QtImageGraphics g) + { + super( g ); + } + + private void scheduleUpdate() + { + } + + public void dispose() + { + super.dispose(); + peer.toolkit.sync(); + peer.QtUpdate(); + } + + public void draw(Shape s) + { + super.draw(s); + scheduleUpdate(); + } + + public void fill(Shape s) + { + super.fill(s); + scheduleUpdate(); + } + + public void drawString(String string, int x, int y) + { + super.drawString( string, x, y ); + scheduleUpdate(); + } + + public void drawString(String string, float x, float y) + { + super.drawString( string, x, y ); + scheduleUpdate(); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + super.drawLine(x1, y1, x2, y2); + scheduleUpdate(); + } + + public boolean drawImage(Image image, + AffineTransform Tx, + ImageObserver obs) + { + boolean r = super.drawImage(image, Tx, obs); + scheduleUpdate(); + return r; + } + + public boolean drawImage(Image image, int x, int y, Color bgcolor, + ImageObserver observer) + { + boolean r = super.drawImage(image, x, y, bgcolor, observer); + scheduleUpdate(); + return r; + } + + public boolean drawImage(Image image, + int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer) + { + boolean r = super.drawImage( image, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, + bgcolor, observer); + scheduleUpdate(); + return r; + } + + public boolean drawImage(Image image, int x, int y, + int width, int height, Color bgcolor, + ImageObserver observer) + { + boolean r = super.drawImage(image, x, y, width, height, bgcolor, + observer); + scheduleUpdate(); + return r; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtImageGraphics.java b/libjava/classpath/gnu/java/awt/peer/qt/QtImageGraphics.java new file mode 100644 index 000000000..bba25e068 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtImageGraphics.java @@ -0,0 +1,139 @@ +/* QtImageGraphics.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Color; +import java.awt.GraphicsConfiguration; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Rectangle; +import java.util.Stack; + +/** + * QtComponentPainter is a Graphics2D context for painting to QtImage and + * QtVolatileImages. + */ +public class QtImageGraphics extends QtGraphics +{ + Image parentImage; + Stack owners; + QtImageGraphics topParent; + + public QtImageGraphics(Image image) + { + if(!( image instanceof QtVolatileImage || image instanceof QtImage)) + throw new IllegalArgumentException("Cannot create QtImageGraphics for a non-QImage context."); + + owners = new Stack(); + owners.push(this); + topParent = null; + int w, h; + if(image instanceof QtImage) + { + w = ((QtImage)image).width; + h = ((QtImage)image).height; + initImage((QtImage) image ); + ((QtImage)image).putPainter( this ); + } + else + { + w = ((QtVolatileImage)image).width; + h = ((QtVolatileImage)image).height; + initVolatileImage((QtVolatileImage) image ); + ((QtVolatileImage)image).putPainter( this ); + } + + parentImage = image; + initialClip = new Rectangle( 0, 0, w, h ); + setClip( initialClip ); + setBackground(Color.white); // fixme + currentAlpha = 1.0; + setColor(Color.black); + setup(); + } + + /** + * Copying constructor + */ + QtImageGraphics( QtImageGraphics g ) + { + super( g ); + parentImage = g.parentImage; + if(parentImage instanceof QtImage) + ((QtImage)parentImage).putPainter( this ); + else + ((QtVolatileImage)parentImage).putPainter( this ); + } + + public void dispose() + { + delete(); + if( parentImage instanceof QtImage ) + ((QtImage)parentImage).removePainter( this ); + else + ((QtVolatileImage)parentImage).removePainter( this ); + } + + /** + * Create a copy of this context. + */ + public Graphics create() + { + return new QtImageGraphics( this ); + } + + /** + * Copy an area. + */ + public void copyArea(int x, int y, int width, int height, + int dx, int dy) + { + if(parentImage instanceof QtImage) + ((QtImage)parentImage).copyArea(x, y, width, height, dx, dy); + else + ((QtVolatileImage)parentImage).copyArea(x, y, width, height, dx, dy); + } + + /** + * Returns the GraphicsConfiguration of the context component. + */ + public GraphicsConfiguration getDeviceConfiguration() + { + throw new UnsupportedOperationException("Not implemented yet"); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtLabelPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtLabelPeer.java new file mode 100644 index 000000000..80acd491d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtLabelPeer.java @@ -0,0 +1,62 @@ +/* QtLabelPeer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Label; +import java.awt.peer.LabelPeer; + +public class QtLabelPeer extends QtComponentPeer implements LabelPeer +{ + public QtLabelPeer( QtToolkit kit, Label owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setText( ((Label)owner).getText() ); + setAlignment( ((Label)owner).getAlignment() ); + } + + public native void setAlignment( int alignment ); + + public native void setText( String label ); +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtListPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtListPeer.java new file mode 100644 index 000000000..14ae2a0cd --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtListPeer.java @@ -0,0 +1,188 @@ +/* QtListPeer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Dimension; +import java.awt.List; +import java.awt.event.ActionEvent; +import java.awt.event.ItemEvent; +import java.awt.peer.ListPeer; + +public class QtListPeer extends QtComponentPeer implements ListPeer +{ + public QtListPeer( QtToolkit kit, List owner ) + { + super( kit, owner ); + } + + public native void init(); + + protected void setup() + { + super.setup(); + List o = (List)owner; + // Multiple selection + setMultipleMode(o.isMultipleMode()); + // Add initial list items. + String[] items = o.getItems(); + for (int i = 0; i < items.length; i++) + add(items[i], i); + + // Initial selections. + int[] selected = o.getSelectedIndexes(); + for (int i = 0; i < selected.length; i++) + select(selected[i]); + + // If no initial selection, use 0. + if(selected.length == 0 && items.length > 0) + select( 0 ); + } + + private boolean ignoreNextSelect = false; + + /** + * Called back when a row is selected. -1 if no row is selected. + */ + private void fireChoice( int index ) + { + ignoreNextSelect = true; + if( index == -1) + ((List)owner).deselect( ((List)owner).getSelectedIndex() ); + else + { + ((List)owner).select( index ); + ItemEvent e = new ItemEvent((List)owner, + ItemEvent.ITEM_STATE_CHANGED, + ""+index, + ItemEvent.SELECTED); + QtToolkit.eventQueue.postEvent(e); + } + } + + /** + * Called back when an item is double-clicked. + */ + private void itemDoubleClicked( int index, int modifiers ) + { + ActionEvent e = new ActionEvent(owner, + ActionEvent.ACTION_PERFORMED, + ((List)owner).getItem( index ), + System.currentTimeMillis(), + modifiers); + QtToolkit.eventQueue.postEvent(e); + } + + private native void select(int index, boolean selected); + + // ************ Public methods ********************* + + public native void add(String item, int index); + + public void addItem(String item, int index) + { + add(item, index); + } + + public void clear() + { + removeAll(); + } + + /** + * Deletes items from the starting index to the ending index (inclusive). + */ + public native void delItems(int start_index, int end_index); + + public void deselect(int index) + { + if( ignoreNextSelect == true ) + ignoreNextSelect = false; + else + select(index, false); + } + + public native int[] getSelectedIndexes(); + + public native void makeVisible(int index); + + public Dimension minimumSize(int s) + { + return getMinimumSize(s); + } + + public Dimension preferredSize(int s) + { + return getPreferredSize(s); + } + + public void removeAll() + { + delItems(0, ((List)owner).getItemCount() - 1); + } + + public void select(int index) + { + if( ignoreNextSelect == true ) + ignoreNextSelect = false; + else + select(index, true); + } + + /** + * Sets multiple-selection mode. + * Note there's a bug in multiple selection in Qt 4.0.0, use 4.0.1. + */ + public native void setMultipleMode(boolean multi); + + public void setMultipleSelections(boolean multi) + { + setMultipleMode(multi); + } + + public Dimension getPreferredSize(int s) + { + // FIXME + return getPreferredSize(); + } + + public Dimension getMinimumSize(int s) + { + // FIXME + return getMinimumSize(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtMenuBarPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuBarPeer.java new file mode 100644 index 000000000..962d76d41 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuBarPeer.java @@ -0,0 +1,101 @@ +/* QtMenuBarPeer.java -- Qt peer for a menu bar. + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.peer.MenuBarPeer; + +public class QtMenuBarPeer extends QtMenuComponentPeer implements MenuBarPeer +{ + public QtMenuBarPeer( QtToolkit kit, MenuBar owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + } + + /** + * Recurses the menubar adding menus (and menu items), + * called from the Frame peer. + */ + void addMenus() + { + MenuBar o = (MenuBar)owner; + int help = (o.getHelpMenu() != null) ? 1 : 0; + for (int i = 0; i < o.getMenuCount() - help; i++) + addMenu( o.getMenu(i) ); + if(o.getHelpMenu() != null) + addHelpMenu( o.getHelpMenu() ); + } + + private native void addMenu( QtMenuPeer mp ); + + private native void addHelpMenu( QtMenuPeer mp ); + + private native void delMenu( QtMenuPeer mp ); + + // ************ Public methods ********************* + + public void addMenu( Menu m ) + { + if (m.getPeer() == null) + m.addNotify(); + ((QtMenuPeer)m.getPeer()).addItems(); + addMenu( (QtMenuPeer)m.getPeer() ); + } + + public void addHelpMenu( Menu m ) + { + if (m.getPeer() == null) + m.addNotify(); + ((QtMenuPeer)m.getPeer()).addItems(); + addHelpMenu( (QtMenuPeer)m.getPeer() ); + } + + public void delMenu( int index ) + { + Menu m = ((MenuBar)owner).getMenu( index ); + if(m != null) + delMenu( (QtMenuPeer)m.getPeer() ); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtMenuComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuComponentPeer.java new file mode 100644 index 000000000..2050bef06 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuComponentPeer.java @@ -0,0 +1,94 @@ +/* QtMenuComponentPeer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Font; +import java.awt.MenuComponent; +import java.awt.peer.MenuComponentPeer; + +public class QtMenuComponentPeer extends NativeWrapper + implements MenuComponentPeer +{ + protected QtToolkit toolkit; + protected MenuComponent owner; + + public QtMenuComponentPeer( QtToolkit kit, MenuComponent owner ) + { + this.toolkit = kit; + this.owner = owner; + nativeObject = 0; + synchronized(this) + { + callInit(); // Calls the init method FROM THE MAIN THREAD. + try + { + wait(); // Wait for the thing to be created. + } + catch(InterruptedException e) + { + } + } + setup(); + } + + protected native void callInit(); + + protected void init() + { + } + + protected void setup() + { + } + + public void finalize() + { + dispose(); + } + + // ************ Public methods ********************* + + public native void dispose(); + + public void setFont(Font font) + { + // TODO Auto-generated method stub + + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtMenuItemPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuItemPeer.java new file mode 100644 index 000000000..2b77540a5 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuItemPeer.java @@ -0,0 +1,100 @@ +/* QtMenuItemPeer.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.MenuItem; +import java.awt.CheckboxMenuItem; +import java.awt.event.ActionEvent; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.CheckboxMenuItemPeer; + +public class QtMenuItemPeer extends QtMenuComponentPeer + implements MenuItemPeer, CheckboxMenuItemPeer +{ + public QtMenuItemPeer( QtToolkit toolkit, MenuItem owner ) + { + super(toolkit, owner); + } + + protected void init() + { + String label = ((MenuItem)owner).getLabel(); + create(label, label.equals("-"), (owner instanceof CheckboxMenuItem)); + } + + protected void setup() + { + } + + private native void create(String label, boolean isSeperator, boolean isCheckable); + + public void finalize() + { + dispose(); + } + + public native void dispose(); + + private void fireClick(int modifiers) + { + ActionEvent e = new ActionEvent(owner, + ActionEvent.ACTION_PERFORMED, + ((MenuItem)owner).getActionCommand(), + System.currentTimeMillis(), + (modifiers & 0x2FF)); + QtToolkit.eventQueue.postEvent(e); + } + + // ************ Public methods ********************* + + public void disable() + { + setEnabled(false); + } + + public void enable() + { + setEnabled(true); + } + + public native void setEnabled(boolean b); + + public native void setLabel(String label); + + public native void setState(boolean state); +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtMenuPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuPeer.java new file mode 100644 index 000000000..0f65fecbd --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtMenuPeer.java @@ -0,0 +1,149 @@ +/* QtMenuPeer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Menu; +import java.awt.MenuItem; +import java.awt.PopupMenu; +import java.awt.event.ActionEvent; +import java.awt.peer.MenuPeer; +import java.util.Vector; + +public class QtMenuPeer extends QtMenuComponentPeer implements MenuPeer +{ + Vector items; + boolean itemsAdded; + + public QtMenuPeer( QtToolkit kit, Menu owner ) + { + super( kit, owner ); + itemsAdded = false; + } + + protected native void init(); + + protected void setup() + { + items = new Vector(); + setLabel( ((Menu)owner).getLabel() ); + if( ((Menu)owner).isTearOff() ) + allowTearOff(); + } + + // Recurse the menu tree adding items, + // called from the MenuBar addMenus() method, called from the Frame peer. + void addItems() + { + if(!itemsAdded) + { + Menu o = (Menu)owner; + for( int i=0; i < o.getItemCount(); i++ ) + { + MenuItem ci = o.getItem(i); + if (ci instanceof Menu && ci.getPeer() != null) + ((QtMenuPeer)ci.getPeer()).addItems(); + addItem( ci ); + } + itemsAdded = true; + } + } + + private void fireClick() + { + ActionEvent e = new ActionEvent(owner, + ActionEvent.ACTION_PERFORMED, + ((Menu)owner).getActionCommand()); + QtToolkit.eventQueue.postEvent(e); + } + + private native void allowTearOff(); + + private native void insertSeperator(); + + private native void insertItem(QtMenuItemPeer p); + + private native void insertMenu(QtMenuPeer menu); + + private native void delItem(long ptr); + + private void add(long ptr) + { + items.add(new Long(ptr)); + } + + // ************ Public methods ********************* + + public void addItem( MenuItem item ) + { + if( item instanceof Menu || item instanceof PopupMenu) + insertMenu((QtMenuPeer)item.getPeer()); + else + { + QtMenuItemPeer p = (QtMenuItemPeer)item.getPeer(); + insertItem(p); + } + } + + public void addSeparator() + { + insertSeperator(); + } + + public void delItem( int index ) + { + long ptr = ((Long)items.elementAt(index)).longValue(); + delItem(ptr); + items.removeElementAt(index); + } + + // Inherited methods.. + + public void disable() + { + setEnabled(false); + } + + public void enable() + { + setEnabled(true); + } + + public native void setEnabled(boolean enabled); + + public native void setLabel(String text); +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtPanelPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtPanelPeer.java new file mode 100644 index 000000000..1ac0ca9a6 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtPanelPeer.java @@ -0,0 +1,56 @@ +/* QtPanelPeer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Component; +import java.awt.peer.PanelPeer; + +public class QtPanelPeer extends QtContainerPeer implements PanelPeer +{ + public QtPanelPeer( QtToolkit kit, Component owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtPopupMenuPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtPopupMenuPeer.java new file mode 100644 index 000000000..eb4dae404 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtPopupMenuPeer.java @@ -0,0 +1,76 @@ +/* QtPopupMenuPeer.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Component; +import java.awt.Point; +import java.awt.PopupMenu; +import java.awt.Event; +import java.awt.peer.PopupMenuPeer; + +public class QtPopupMenuPeer extends QtMenuPeer implements PopupMenuPeer +{ + public QtPopupMenuPeer( QtToolkit kit, PopupMenu owner ) + { + super( kit, owner ); + } + + private native void showNative(int x, int y); + + // ************ Public methods ********************* + + /** + * Part of the older API, replaced by event version instead. + */ + public void show (Component origin, int x, int y) + { + if( origin == null ) + throw new NullPointerException("Null parent component."); + addItems(); + + Point p = origin.getLocationOnScreen(); + showNative( (int)p.getX() + x, (int)p.getY() + y ); + } + + public void show (Event e) + { + if (!(e.target instanceof Component)) + throw new IllegalArgumentException("Expecting a component Event target!"); + show((Component)e.target, e.x, e.y); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtRepaintThread.java b/libjava/classpath/gnu/java/awt/peer/qt/QtRepaintThread.java new file mode 100644 index 000000000..6861be8fc --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtRepaintThread.java @@ -0,0 +1,156 @@ +/* QtRepaintThread.java -- Repaint thread implementation + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +/** + * This class does repainting of Component back-buffers. It is undesirable to + * do this directly from the paint callback in QtComponentPeer, because that + * is executed from the main thread. Thus, if a call is made at the same time + * which requires execution by the main thread, and this is sharing a lock with + * paint(), then a deadlock will occur, which must be avoided. In general, + * the main Qt thread should avoid calling into java code as far as possible. + * + */ +public class QtRepaintThread extends Thread +{ + static class RepaintComponent + { + public QtComponentPeer curr; + public RepaintComponent next; + public boolean paintAll; + public int x, y, w, h; + + public RepaintComponent(QtComponentPeer p) + { + curr = p; + next = null; + paintAll = true; + } + + public RepaintComponent(QtComponentPeer p, int x, int y, int w, int h) + { + this(p); + paintAll = false; + this.x = x; + this.y = y; + this.w = w; + this.h = h; + } + } + + RepaintComponent component; + boolean busy; + + public QtRepaintThread() + { + component = null; + } + + public void run() + { + while( true ) + { + try + { + busy = false; + // Wait for a repaint + sleep(100); + busy = true; + } + catch (InterruptedException ie) + { + while( component != null ) + { + try + { + if( component.paintAll ) + { + // update the back-buffer. + component.curr.paintBackBuffer(); + component.curr.QtUpdate(); // trigger a native repaint event + } + else + { + component.curr.paintBackBuffer(component.x, component.y, + component.w, component.h); + component.curr.QtUpdateArea(component.x, component.y, + component.w, component.h); + } + } + catch (InterruptedException e) + { + } + component = component.next; + } + } + } + } + + /** + * Enqueue a component for repainting. + */ + public synchronized void queueComponent(QtComponentPeer p) + { + if( component == null ) + component = new RepaintComponent(p); + else + { + RepaintComponent r = component; + while( r.next != null ) r = r.next; + r.next = new RepaintComponent(p); + } + interrupt(); + } + + /** + * Enqueue a component for repainting. + */ + public synchronized void queueComponent(QtComponentPeer p, int x, int y, + int w, int h) + { + if( component == null ) + component = new RepaintComponent(p, x, y, w, h); + else + { + RepaintComponent r = component; + while( r.next != null ) r = r.next; + r.next = new RepaintComponent(p, x, y, w, h); + } + interrupt(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtScreenDevice.java b/libjava/classpath/gnu/java/awt/peer/qt/QtScreenDevice.java new file mode 100644 index 000000000..c7d8a4784 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtScreenDevice.java @@ -0,0 +1,115 @@ +/* QtScreenDevice.java -- Wrapper on a Qt screen Widget + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.DisplayMode; +import java.awt.GraphicsConfigTemplate; +import java.awt.Rectangle; +import java.awt.Window; + +public class QtScreenDevice extends GraphicsDevice +{ + private long nativeObject; + private int id; + private String IDstring; + QtScreenDeviceConfiguration config; + + public QtScreenDevice(int id) + { + this.id = id; + IDstring = "QtScreen" + id; + init( id ); + config = new QtScreenDeviceConfiguration(this); + } + + public native void init( int id ); + public native void dispose(); + + // Package-private methods used by QtScreenDeviceConfiguration + native Rectangle getBounds(); + native int getDpiX(); + native int getDpiY(); + native int depth(); + + // ****************** Public methods *********************** + + public GraphicsConfiguration getBestConfiguration(GraphicsConfigTemplate gct) + { + return config; + } + + public GraphicsConfiguration[] getConfigurations() + { + return new GraphicsConfiguration[]{ config }; + } + + public GraphicsConfiguration getDefaultConfiguration() + { + return config; + } + + public String getIDstring() + { + return IDstring; + } + + public int getType() + { + return TYPE_RASTER_SCREEN; + } + + public boolean isDisplayChangeSupported() + { + return false; + } + + public boolean isFullScreenSupported() + { + return false; + } + + public void setDisplayMode(DisplayMode dm) + { + } + + public void setFullScreenWindow(Window w) + { + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtScreenDeviceConfiguration.java b/libjava/classpath/gnu/java/awt/peer/qt/QtScreenDeviceConfiguration.java new file mode 100644 index 000000000..34de36c09 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtScreenDeviceConfiguration.java @@ -0,0 +1,145 @@ +/* QtScreenDeviceConfiguration.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.ImageCapabilities; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.Rectangle; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.VolatileImage; +import java.awt.geom.AffineTransform; + +public class QtScreenDeviceConfiguration extends GraphicsConfiguration { + + private QtScreenDevice owner; + private Rectangle bounds; + private double dpiX, dpiY; + private int depth; + + public QtScreenDeviceConfiguration(QtScreenDevice owner) + { + this.owner = owner; + bounds = owner.getBounds(); + dpiX = owner.getDpiX(); + dpiY = owner.getDpiY(); + depth = owner.depth(); + } + + public BufferedImage createCompatibleImage(int width, int height) + { + switch( depth ) + { + case 24: + return new BufferedImage(width, height, BufferedImage.TYPE_3BYTE_BGR); + case 16: + return new BufferedImage(width, height, + BufferedImage.TYPE_USHORT_565_RGB); + case 8: + return new BufferedImage(width, height, BufferedImage.TYPE_BYTE_INDEXED); + default: + case 32: + return new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); + } + } + + public BufferedImage createCompatibleImage(int width, int height, int transparency) + { + // FIXME: Take the transpareny flag into account? + // For now, ignore it and just use an alpha channel. + if(depth == 32) + return new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); + return createCompatibleImage(width, height); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height) + { + return new QtVolatileImage( width, height ); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, + ImageCapabilities caps) + { + return createCompatibleVolatileImage( width, height ); + } + + public Rectangle getBounds() + { + return bounds; + } + + public ColorModel getColorModel() + { + // FIXME? + return QtToolkit.getDefaultToolkit().getColorModel(); + } + + public ColorModel getColorModel(int transparency) + { + // FIXME? + return QtToolkit.getDefaultToolkit().getColorModel(); + } + + public AffineTransform getDefaultTransform() + { + return new AffineTransform(); + } + + public GraphicsDevice getDevice() + { + return owner; + } + + /** + * Returns the transform which transforms from this display's resolution + * to a 72 DPI resolution. + */ + public AffineTransform getNormalizingTransform() + { + AffineTransform nTrans = new AffineTransform(); + nTrans.scale( 72.0 / dpiX, 72.0 / dpiY ); + return nTrans; + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, + int transparency) + { + return createCompatibleVolatileImage(width, height); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtScrollPanePeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtScrollPanePeer.java new file mode 100644 index 000000000..079d06de7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtScrollPanePeer.java @@ -0,0 +1,90 @@ +/* QtScrollPanePeer.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Adjustable; +import java.awt.Insets; +import java.awt.ScrollPane; +import java.awt.peer.ScrollPanePeer; + +public class QtScrollPanePeer extends QtContainerPeer implements ScrollPanePeer +{ + public QtScrollPanePeer( QtToolkit kit, ScrollPane owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setPolicy( ((ScrollPane)owner).getScrollbarDisplayPolicy() ); + } + + private native void setPolicy(int policy); + + // ************ Public methods ********************* + + public native void childResized(int width, int height); + + public native int getHScrollbarHeight(); + + public native int getVScrollbarWidth(); + + public native void setScrollPosition(int x, int y); + + public Insets getInsets() + { + // FIXME : more accurate? + return new Insets(5 + getHScrollbarHeight(), // Top + 5 + getVScrollbarWidth(), // Left + 5, // Bottom + 5); // Right + } + + public void setUnitIncrement(Adjustable item, int inc) + { + // FIXME + } + + public void setValue(Adjustable item, int value) + { + // FIXME + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtScrollbarPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtScrollbarPeer.java new file mode 100644 index 000000000..694287131 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtScrollbarPeer.java @@ -0,0 +1,80 @@ +/* QtScrollbarPeer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Scrollbar; +import java.awt.event.AdjustmentEvent; +import java.awt.peer.ScrollbarPeer; + +public class QtScrollbarPeer extends QtComponentPeer implements ScrollbarPeer +{ + public QtScrollbarPeer( QtToolkit kit, Scrollbar owner ) + { + super( kit, owner ); + } + + public native void init(); + + protected void setup() + { + super.setup(); + Scrollbar o = (Scrollbar)owner; + setValues(o.getValue(), o.getVisible(), o.getMinimum(), o.getMaximum()); + setOrientation(o.getOrientation()); + setLineIncrement(o.getLineIncrement()); + setPageIncrement(o.getPageIncrement()); + } + + private native void setOrientation(int orientation); + + private void fireMoved(int type, int value) + { + AdjustmentEvent e = new AdjustmentEvent((Scrollbar)owner, + AdjustmentEvent.ADJUSTMENT_VALUE_CHANGED, + type, value); + QtToolkit.eventQueue.postEvent(e); + } + + // ************ Public methods ********************* + + public native void setLineIncrement(int inc); + + public native void setPageIncrement(int inc); + + public native void setValues(int value, int visible, int min, int max); +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtTextAreaPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtTextAreaPeer.java new file mode 100644 index 000000000..a5aff58ef --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtTextAreaPeer.java @@ -0,0 +1,179 @@ +/* QtTextAreaPeer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.TextArea; +import java.awt.event.TextEvent; +import java.awt.im.InputMethodRequests; +import java.awt.peer.TextAreaPeer; + +public class QtTextAreaPeer extends QtComponentPeer implements TextAreaPeer +{ + public QtTextAreaPeer( QtToolkit kit, TextArea owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setText(((TextArea)owner).getText()); + setEditable(((TextArea)owner).isEditable()); + } + + /** + * Returns the start (start = true) or end (start = false) of the selection. + */ + private native int getSelection(boolean start); + + /** + * Called back on a text edit. + */ + private void textChanged() + { + TextEvent e = new TextEvent(owner, TextEvent.TEXT_VALUE_CHANGED); + QtToolkit.eventQueue.postEvent(e); + } + + // ************ Public methods ********************* + + public long filterEvents(long filter) + { + return filter; + } + + public native int getCaretPosition(); + + public Rectangle getCharacterBounds(int pos) + { + // FIXME + return new Rectangle(0,0,0,0); + } + + /** + * Implemented, but who uses it? + */ + public native int getIndexAtPoint(int x, int y); + +// public void reshape(int x, int y, +// int width, int height) +// { +// if(width != 0 || height != 0) +// super.reshape(x, y, width, height); +// else +// super.reshape(x, y, 10, 10); +// } + + public Dimension getMinimumSize(int rows, int cols) + { + // FIXME + return getMinimumSize(); + } + + public Dimension getPreferredSize(int rows, int cols) + { + // FIXME + return getPreferredSize(); + } + + public int getSelectionEnd() + { + return getSelection(false); + } + + public int getSelectionStart() + { + return getSelection(true); + } + + public native String getText(); + + public void insert(String text, int pos) + { + // Not very efficient, no. + String s = getText(); + setText(s.substring(0, pos) + text + s.substring(pos)); + } + + public void insertText(String text, int pos) + { + insert(text, pos); + } + + public Dimension minimumSize(int rows, int cols) + { + return getMinimumSize(rows, cols); + } + + public Dimension preferredSize(int rows, int cols) + { + return getPreferredSize(rows, cols); + } + + public void replaceRange(String insert, int start_pos, int end_pos) + { + // Not very efficient, no. + String text = getText(); + String right = text.substring(0, start_pos); + String left = text.substring(end_pos); + setText(right + insert + left); + } + + public void replaceText(String text, int start_pos, int end_pos) + { + replaceRange(text, start_pos, end_pos); + } + + public native void setText(String text); + + public native void select(int start_pos, int end_pos); + + public native void setEditable(boolean editable); + + public native void setCaretPosition(int pos); + + public InputMethodRequests getInputMethodRequests() + { + // TODO Auto-generated method stub + return null; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtTextFieldPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtTextFieldPeer.java new file mode 100644 index 000000000..f92943202 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtTextFieldPeer.java @@ -0,0 +1,159 @@ +/* QtTextFieldPeer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Dimension; +import java.awt.Rectangle; +import java.awt.TextField; +import java.awt.event.TextEvent; +import java.awt.im.InputMethodRequests; +import java.awt.peer.TextFieldPeer; + +public class QtTextFieldPeer extends QtComponentPeer implements TextFieldPeer +{ + public QtTextFieldPeer( QtToolkit kit, TextField owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + setText(((TextField)owner).getText()); + setEditable(((TextField)owner).isEditable()); + } + + /** + * Called back on a text edit. + */ + private void textChanged() + { + TextEvent e = new TextEvent(owner, TextEvent.TEXT_VALUE_CHANGED); + QtToolkit.eventQueue.postEvent(e); + } + + /** + * Returns the start (start = true) or end (start = false) of the selection. + */ + private native int getSelection(boolean start); + + private native Dimension getMinimumSizeNative(int columns); + + private native Dimension getPreferredSizeNative(int columns); + + // ************ Public methods ********************* + + public long filterEvents(long e) + { + return e; + } + + public native int getCaretPosition(); + + public Rectangle getCharacterBounds(int i) + { + return new Rectangle(0,0,0,0); + } + + public int getIndexAtPoint(int x, int y) + { + // FIXME + return 0; + } + + public Dimension getMinimumSize(int columns) + { + Dimension d = getMinimumSizeNative( columns ); + if ( d == null ) + return new Dimension(10, 10); + return d; + } + + public Dimension getPreferredSize(int columns) + { + Dimension d = getPreferredSizeNative( columns ); + if ( d == null ) + return owner.getSize(); + return d; + } + + public int getSelectionEnd() + { + return getSelection(false); + } + + public int getSelectionStart() + { + return getSelection(true); + } + + public native String getText(); + + public Dimension minimumSize(int cols) + { + return getMinimumSize(cols); + } + + public Dimension preferredSize(int cols) + { + return getPreferredSize(cols); + } + + public native void select(int selStart, int selEnd); + + public native void setCaretPosition(int pos); + + public void setEchoCharacter(char c) + { + setEchoChar(c); + } + + public native void setEchoChar(char echoChar); + + public native void setEditable(boolean editable); + + public native void setText(String l); + + public InputMethodRequests getInputMethodRequests() + { + // TODO Auto-generated method stub + return null; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtToolkit.java b/libjava/classpath/gnu/java/awt/peer/qt/QtToolkit.java new file mode 100644 index 000000000..9f8a691c6 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtToolkit.java @@ -0,0 +1,470 @@ +/* QtToolkit.java -- + Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import gnu.java.awt.ClasspathToolkit; +import gnu.java.awt.EmbeddedWindow; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.peer.EmbeddedWindowPeer; + +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.PrintJob; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Window; +import java.awt.datatransfer.Clipboard; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.event.AWTEventListener; +import java.awt.im.InputMethodHighlight; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.ButtonPeer; +import java.awt.peer.CanvasPeer; +import java.awt.peer.CheckboxMenuItemPeer; +import java.awt.peer.CheckboxPeer; +import java.awt.peer.ChoicePeer; +import java.awt.peer.DialogPeer; +import java.awt.peer.FileDialogPeer; +import java.awt.peer.FontPeer; +import java.awt.peer.FramePeer; +import java.awt.peer.LabelPeer; +import java.awt.peer.ListPeer; +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.PopupMenuPeer; +import java.awt.peer.RobotPeer; +import java.awt.peer.ScrollPanePeer; +import java.awt.peer.ScrollbarPeer; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.WindowPeer; +import java.io.InputStream; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +public class QtToolkit extends ClasspathToolkit +{ + public static EventQueue eventQueue = null; // the native event queue + public static QtRepaintThread repaintThread = null; + public static MainQtThread guiThread = null; + public static QtGraphicsEnvironment graphicsEnv = null; + + private static void initToolkit() + { + eventQueue = new EventQueue(); + repaintThread = new QtRepaintThread(); + System.loadLibrary("qtpeer"); + + String theme = null; + try + { + String style = System.getProperty("qtoptions.style"); + if(style != null) + theme = style; + } + catch(SecurityException e) + { + } + catch(IllegalArgumentException e) + { + } + + boolean doublebuffer = true; + try + { + String style = System.getProperty("qtoptions.nodoublebuffer"); + if(style != null) + doublebuffer = false; + } + catch(SecurityException e) + { + } + catch(IllegalArgumentException e) + { + } + + guiThread = new MainQtThread( theme, doublebuffer ); + guiThread.start(); + repaintThread.start(); + } + + /** + * Construct the toolkit! + */ + public QtToolkit() + { + if( guiThread == null ) + initToolkit(); + + // make sure the GUI thread has started. + while (!guiThread.isRunning()) + ; + + if( graphicsEnv == null ) + graphicsEnv = new QtGraphicsEnvironment( this ); + } + + native String[] nativeFontFamilies(); + + native int numScreens(); + + native int defaultScreen(); + + // ************ Public methods ********************* + + public synchronized native void beep(); + + public int checkImage(Image image, int w, int h, ImageObserver observer) + { + if(image instanceof QtImage) + return ((QtImage)image).checkImage(observer); + + return ImageObserver.ERROR; // FIXME + } + + protected ButtonPeer createButton( Button target ) + { + return new QtButtonPeer( this, target ); + } + + protected CanvasPeer createCanvas(Canvas target) + { + return new QtCanvasPeer( this, target ); + } + + protected CheckboxPeer createCheckbox(Checkbox target) + { + return new QtCheckboxPeer( this, target ); + } + + protected ChoicePeer createChoice(Choice target) + { + return new QtChoicePeer( this, target ); + } + + protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) + { + return new QtMenuItemPeer( this, target ); + } + + public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent dge) + { + throw new RuntimeException("Not implemented"); + } + + protected FramePeer createFrame(Frame target) + { + return new QtFramePeer( this, target ); + } + + protected FileDialogPeer createFileDialog(FileDialog target) + { + return new QtFileDialogPeer( this, target ); + } + + public Image createImage(ImageProducer producer) + { + return new QtImage( producer ); + } + + public Image createImage(byte[] imageData, + int imageOffset, + int imageLength) + { + byte[] dataCopy = new byte[imageLength]; + System.arraycopy(imageData, imageOffset, dataCopy, 0, imageLength); + return new QtImage( dataCopy ); + } + + public Image createImage(String filename) + { + return new QtImage( filename ); + } + + public Image createImage(URL url) + { + return new QtImage( url ); + } + + protected TextFieldPeer createTextField(TextField target) + { + return new QtTextFieldPeer(this,target); + } + + protected LabelPeer createLabel(Label target) + { + return new QtLabelPeer( this, target ); + } + + protected ListPeer createList(List target) + { + return new QtListPeer( this, target ); + } + + protected ScrollbarPeer createScrollbar(Scrollbar target) + { + return new QtScrollbarPeer( this, target ); + } + + protected ScrollPanePeer createScrollPane(ScrollPane target) + { + return new QtScrollPanePeer( this, target ); + } + + protected TextAreaPeer createTextArea(TextArea target) + { + return new QtTextAreaPeer( this, target ); + } + + protected PanelPeer createPanel(Panel target) + { + return new QtPanelPeer( this, target); + } + + protected WindowPeer createWindow(Window target) + { + return new QtWindowPeer( this, target ); + } + + protected DialogPeer createDialog(Dialog target) + { + return new QtDialogPeer( this, target ); + } + + protected MenuBarPeer createMenuBar(MenuBar target) + { + return new QtMenuBarPeer( this, target ); + } + + protected MenuPeer createMenu(Menu target) + { + return new QtMenuPeer( this, target ); + } + + protected PopupMenuPeer createPopupMenu(PopupMenu target) + { + return new QtPopupMenuPeer( this, target ); + } + + protected MenuItemPeer createMenuItem(MenuItem target) + { + return new QtMenuItemPeer( this, target ); + } + + /** + * @since 1.4 + */ + public AWTEventListener[] getAWTEventListeners() + { + return null; // FIXME + } + + /** + * @since 1.4 + */ + public AWTEventListener[] getAWTEventListeners(long mask) + { + return null; // FIXME + } + + public ColorModel getColorModel() + { + return new DirectColorModel(32, + 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000); + } + + /** + * Just return the defaults. + */ + public String[] getFontList() + { + String[] builtIn = new String[] { "Dialog", + "DialogInput", + "Monospaced", + "Serif", + "SansSerif" }; + String[] nat = nativeFontFamilies(); + String[] allFonts = new String[ nat.length + 5 ]; + System.arraycopy(builtIn, 0, allFonts, 0, 5); + System.arraycopy(nat, 0, allFonts, 5, nat.length); + return allFonts; + } + + public FontMetrics getFontMetrics(Font font) + { + return new QtFontMetrics(font); + } + + protected FontPeer getFontPeer(String name, + int style) + { + Map attrs = new HashMap (); + ClasspathFontPeer.copyStyleToAttrs(style, attrs); + ClasspathFontPeer.copySizeToAttrs(12, attrs); // Default size is 12. + return getClasspathFontPeer (name, attrs); + } + + public Image getImage(String filename) + { + return new QtImage(filename); + } + + public Image getImage(URL url) + { + return createImage( url ); + } + + public PrintJob getPrintJob(Frame frame, + String jobtitle, + Properties props) + { + SecurityManager sm; + sm = System.getSecurityManager(); + if (sm != null) + sm.checkPrintJobAccess(); + + throw new RuntimeException("Not implemented"); + } + + public Clipboard getSystemClipboard() + { + throw new RuntimeException("Not implemented"); + } + + protected EventQueue getSystemEventQueueImpl() + { + return eventQueue; + } + + public native Dimension getScreenSize(); + + public native int getScreenResolution(); + + public Map mapInputMethodHighlight(InputMethodHighlight highlight) + { + return null; // FIXME + } + + public boolean prepareImage(Image image, int w, int h, ImageObserver observer) + { + if(image instanceof QtImage) + return true; + return false; // FIXME? + } + + public native void sync(); + + // ********************** ClasspathToolkit methods + + public GraphicsEnvironment getLocalGraphicsEnvironment() + { + return graphicsEnv; + } + + public ClasspathFontPeer getClasspathFontPeer (String name, Map attrs) + { + return new QtFontPeer (name, attrs); + } + + // FIXME + public Font createFont(int format, InputStream stream) + { + throw new UnsupportedOperationException(); + } + + // FIXME + public RobotPeer createRobot (GraphicsDevice screen) throws AWTException + { + throw new UnsupportedOperationException(); + } + + public EmbeddedWindowPeer createEmbeddedWindow(EmbeddedWindow w) + { + // return new QtEmbeddedWindowPeer( this, w ); + return null; + } + + @Override + public boolean isModalExclusionTypeSupported + (Dialog.ModalExclusionType modalExclusionType) + { + return false; + } + + @Override + public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) + { + return false; + } + + +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtVolatileImage.java b/libjava/classpath/gnu/java/awt/peer/qt/QtVolatileImage.java new file mode 100644 index 000000000..a203de0d0 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtVolatileImage.java @@ -0,0 +1,434 @@ +/* QtVolatileImage.java -- + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Color; +import java.awt.Image; +import java.awt.ImageCapabilities; +import java.awt.GraphicsConfiguration; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.MemoryImageSource; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.VolatileImage; +import java.util.Hashtable; +import java.util.WeakHashMap; + +/** + * QtVolatileImage - wraps a QImage + * + */ +public class QtVolatileImage extends VolatileImage +{ + int width = -1, height = -1; + + /** + * Properties. + */ + Hashtable props; + + /** + * Pointer to the QImage + */ + long nativeObject; + + /* + * The 32-bit AARRGGBB format the uses. + */ + static ColorModel nativeModel = new DirectColorModel(32, + 0x00FF0000, + 0x0000FF00, + 0x000000FF, + 0xFF000000); + + /** + * Clears the image to RGBA 0 + */ + public native void clear(); + + /** + * Returns a copy of the pixel data as a java array. + */ + private native int[] getPixels(); + + /** + * Allocates a QImage + */ + private native void createImage(); + + /** + * HashMap of Graphics objects painting on this Image. + */ + WeakHashMap painters; + + /** + * Flags if this image is to be destroyed. + */ + boolean killFlag; + + /** + * Frees the above. + */ + private native void freeImage(); + + /** + * Blit a QImage + */ + public native void blit(QtImage i); + public native void blit(QtImage i, int x, int y, int w, int h); + + /** + * Sets the image to scaled copy of src image. hints are rendering hints. + */ + private native void createScaledImage(QtVolatileImage src, int hints); + + /** + * Draws the image optionally composited. + */ + private native void drawPixels (QtGraphics gc, + int bg_red, int bg_green, int bg_blue, + int x, int y, + boolean composite); + /** + * Draws the image, optionally scaled and composited. + */ + private native void drawPixelsScaled (QtGraphics gc, + int bg_red, int bg_green, int bg_blue, + int x, int y, int width, int height, + boolean composite); + + /** + * Draws the image transformed. + */ + private native void drawPixelsTransformed (QtGraphics gc, QMatrix transform); + + /** + * Draws the image scaled flipped and optionally composited. + */ + native void drawPixelsScaledFlipped (QtGraphics gc, + int bg_red, int bg_green, + int bg_blue, + boolean flipX, boolean flipY, + int srcX, int srcY, + int srcWidth, int srcHeight, + int dstX, int dstY, + int dstWidth, int dstHeight, + boolean composite); + + /** + * Constructs an empty QtVolatileImage. + */ + public QtVolatileImage (int width, int height) + { + this.width = width; + this.height = height; + props = new Hashtable(); + createImage(); + clear(); + } + + /** + * Constructs a scaled version of the src bitmap, using Qt + */ + private QtVolatileImage (QtVolatileImage src, int width, int height, + int hints) + { + this.width = width; + this.height = height; + props = new Hashtable(); + + createScaledImage(src, hints); + } + + + public void finalize() + { + dispose(); + } + + public void dispose() + { + if( painters == null || painters.isEmpty() ) + freeImage(); + else + killFlag = true; // can't destroy image yet. + // Do so when all painters are gone. + } + + // java.awt.Image methods //////////////////////////////////////////////// + + public int getWidth (ImageObserver observer) + { + return getWidth(); + } + + public int getHeight (ImageObserver observer) + { + return getHeight(); + } + + public Object getProperty (String name, ImageObserver observer) + { + Object value = props.get (name); + return (value == null) ? UndefinedProperty : value; + } + + /** + * Returns the source of this image. + */ + public ImageProducer getSource () + { + return new MemoryImageSource(width, height, nativeModel, getPixels(), + 0, width); + } + + void putPainter(QtImageGraphics g) + { + if( painters == null ) + painters = new WeakHashMap(); + painters.put( g, "dummy" ); + } + + void removePainter(QtImageGraphics g) + { + painters.remove( g ); + if( killFlag && painters.isEmpty() ) + freeImage(); + } + + /** + * Creates a Graphics context for this image. + */ + public Graphics getGraphics () + { + QtImageGraphics g = new QtImageGraphics( this ); + putPainter( g ); + return g; + } + + /** + * Returns a scaled instance of this image. + */ + public Image getScaledInstance(int width, + int height, + int hints) + { + if (width <= 0 || height <= 0) + throw new IllegalArgumentException("Width and height of scaled bitmap"+ + "must be >= 0"); + + return new QtVolatileImage(this, width, height, hints); + } + + /** + */ + public void flush () + { + // FIXME ? + } + + /** + * Returns the image status, used by QtToolkit + */ + public int checkImage (ImageObserver observer) + { + return ImageObserver.ALLBITS | ImageObserver.WIDTH | ImageObserver.HEIGHT; + } + + // Drawing methods //////////////////////////////////////////////// + + /** + * Draws an image with eventual scaling/transforming. + */ + public boolean drawImage (QtGraphics g, QMatrix matrix, + ImageObserver observer) + { + drawPixelsTransformed (g, matrix); + return true; + } + + /** + * Draws an image to the QtGraphics context, at (x,y) with optional + * compositing with a background color. + */ + public boolean drawImage (QtGraphics g, int x, int y, + Color bgcolor, ImageObserver observer) + { + if(bgcolor != null) + drawPixels(g, bgcolor.getRed (), bgcolor.getGreen (), + bgcolor.getBlue (), x, y, true); + else + drawPixels(g, 0, 0, 0, x, y, false); + + return true; + } + + /** + * Draws an image to the QtGraphics context, at (x,y) scaled to + * width and height, with optional compositing with a background color. + */ + public boolean drawImage (QtGraphics g, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + if(bgcolor != null) + drawPixelsScaled(g, bgcolor.getRed (), bgcolor.getGreen (), + bgcolor.getBlue (), x, y, width, height, true); + else + drawPixelsScaled(g, 0, 0, 0, x, y, width, height, false); + + return true; + } + + /** + * Draws an image with eventual scaling/transforming. + */ + public boolean drawImage (QtGraphics g, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + Color bgcolor, ImageObserver observer) + { + boolean flipX = (dx1 > dx2)^(sx1 > sx2); + boolean flipY = (dy1 > dy2)^(sy1 > sy2); + int dstWidth = Math.abs (dx2 - dx1); + int dstHeight = Math.abs (dy2 - dy1); + int srcWidth = Math.abs (sx2 - sx1); + int srcHeight = Math.abs (sy2 - sy1); + int srcX = (sx1 < sx2) ? sx1 : sx2; + int srcY = (sy1 < sy2) ? sy1 : sy2; + int dstX = (dx1 < dx2) ? dx1 : dx2; + int dstY = (dy1 < dy2) ? dy1 : dy2; + + // Clipping. This requires the dst to be scaled as well, + if (srcWidth > width) + { + dstWidth = (int)((double)dstWidth*((double)width/(double)srcWidth)); + srcWidth = width - srcX; + } + + if (srcHeight > height) + { + dstHeight = (int)((double)dstHeight*((double)height/(double)srcHeight)); + srcHeight = height - srcY; + } + + if (srcWidth + srcX > width) + { + dstWidth = (int)((double)dstWidth * (double)(width - srcX)/(double)srcWidth); + srcWidth = width - srcX; + } + + if (srcHeight + srcY > height) + { + dstHeight = (int)((double)dstHeight * (double)(width - srcY)/(double)srcHeight); + srcHeight = height - srcY; + } + + if ( srcWidth <= 0 || srcHeight <= 0 || dstWidth <= 0 || dstHeight <= 0) + return true; + + if(bgcolor != null) + drawPixelsScaledFlipped (g, bgcolor.getRed (), bgcolor.getGreen (), + bgcolor.getBlue (), + flipX, flipY, + srcX, srcY, + srcWidth, srcHeight, + dstX, dstY, + dstWidth, dstHeight, + true); + else + drawPixelsScaledFlipped (g, 0, 0, 0, flipX, flipY, + srcX, srcY, srcWidth, srcHeight, + dstX, dstY, dstWidth, dstHeight, + false); + return true; + } + + public native void copyArea(int x, int y, int width, int height, + int dx, int dy); + + //******************** VolatileImage stuff ******************** + + public boolean contentsLost() + { + return false; + } + + public Graphics2D createGraphics() + { + QtImageGraphics g = new QtImageGraphics(this); + putPainter( g ); + return g; + } + + public ImageCapabilities getCapabilities() + { + return new ImageCapabilities(false) + { + public boolean isTrueVolatile() + { + return false; + } + }; + } + + public int getHeight() + { + return height; + } + + public BufferedImage getSnapshot() + { + BufferedImage bi = new BufferedImage(width, height, + BufferedImage.TYPE_INT_ARGB_PRE); + bi.setRGB( 0, 0, width, height, getPixels(), 0, width); + return bi; + } + + public int getWidth() + { + return width; + } + + public int validate(GraphicsConfiguration gc) + { + return IMAGE_OK; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/qt/QtWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/qt/QtWindowPeer.java new file mode 100644 index 000000000..2dfe2ec5a --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/qt/QtWindowPeer.java @@ -0,0 +1,105 @@ +/* QtWindowPeer.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.qt; + +import java.awt.Component; +import java.awt.peer.WindowPeer; + +public class QtWindowPeer extends QtContainerPeer implements WindowPeer +{ + public QtWindowPeer( QtToolkit kit, Component owner ) + { + super( kit, owner ); + } + + protected native void init(); + + protected void setup() + { + super.setup(); + } + + // ************ Public methods ********************* + + public native void toBack(); + + public native void toFront(); + + /* + * Belongs to Frame and Dialog, but no sense in duplicating code. + */ + public native void setTitle(String title); + + public void updateAlwaysOnTop() + { + // TODO Auto-generated method stub + + } + + public boolean requestWindowFocus() + { + // TODO Auto-generated method stub + return false; + } + + public void updateIconImages() + { + // TODO: Implement properly. + } + + public void updateMinimumSize() + { + // TODO: Implement properly. + } + + public void setModalBlocked(java.awt.Dialog d, boolean b) + { + // TODO: Implement properly. + } + + public void updateFocusableWindowState() + { + // TODO: Implement properly. + } + + public void setAlwaysOnTop(boolean b) + { + // TODO: Implement properly. + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingButtonPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingButtonPeer.java new file mode 100644 index 000000000..1a42fc953 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingButtonPeer.java @@ -0,0 +1,261 @@ +/* SwingButtonPeer.java -- A Swing based peer for AWT buttons + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Button; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.ButtonPeer; + +import javax.swing.JButton; +import javax.swing.JComponent; + +/** + * A Swing based peer for the AWT button. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingButtonPeer + extends SwingComponentPeer + implements ButtonPeer +{ + + /** + * A specialized Swing button to be used as AWT button. + * + * @author Roman Kennke (kennke@aicas.com) + */ + class SwingButton + extends JButton + implements SwingComponent + { + Button button; + + SwingButton(Button button) + { + this.button = button; + } + + /** + * Overridden so that this method returns the correct value even without a + * peer. + * + * @return the screen location of the button + */ + public Point getLocationOnScreen() + { + return SwingButtonPeer.this.getLocationOnScreen(); + } + + /** + * Overridden so that the isShowing method returns the correct value for the + * swing button, even if it has no peer on its own. + * + * @return true if the button is currently showing, + * false otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (button != null) + retVal = button.isShowing(); + return retVal; + } + + /** + * Overridden, so that the Swing button can create an Image without its + * own peer. + * + * @param w the width of the image + * @param h the height of the image + * + * @return an image + */ + public Image createImage(int w, int h) + { + return SwingButtonPeer.this.createImage(w, h); + } + + /** + * Overridden, so that the Swing button can create a Graphics without its + * own peer. + * + * @return a graphics instance for the button + */ + public Graphics getGraphics() + { + return SwingButtonPeer.this.getGraphics(); + } + + /** + * Returns this button. + * + * @return this button + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to + * processMouseEvent() after having retargetted it to this + * button. + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseEvent(ev); + } + + /** + * Handles mouse motion events by forwarding it to + * processMouseMotionEvent() after having retargetted it to + * this button. + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to + * processKeyEvent() after having retargetted it to this + * button. + * + * @param ev the mouse event + */ + public void handleKeyEvent(KeyEvent ev) + { + ev.setSource(this); + processKeyEvent(ev); + } + + public Container getParent() + { + Container par = null; + if (button != null) + par = button.getParent(); + return par; + } + + /** + * Handles focus events by forwarding it to + * processFocusEvent(). + * + * @param ev the Focus event + */ + public void handleFocusEvent(FocusEvent ev) + { + processFocusEvent(ev); + } + + public void requestFocus() { + SwingButtonPeer.this.requestFocus(awtComponent, false, true, 0); + } + + public boolean requestFocus(boolean temporary) { + return SwingButtonPeer.this.requestFocus(awtComponent, temporary, + true, 0); + } + } + + /** + * Listens for ActionEvents on the Swing button and triggers corresponding + * ActionEvents on the AWT button. + * + * @author Roman Kennke (kennke@aicas.com) + */ + class SwingButtonListener implements ActionListener + { + + /** + * Receives notification when an action was performend on the button. + * + * @param event the action event + */ + public void actionPerformed(ActionEvent event) + { + Button b = (Button) SwingButtonPeer.this.awtComponent; + ActionListener[] l = b.getActionListeners(); + if (l.length == 0) + return; + ActionEvent ev = new ActionEvent(b, ActionEvent.ACTION_PERFORMED, + b.getActionCommand()); + for (int i = 0; i < l.length; ++i) + l[i].actionPerformed(ev); + } + + } + + /** + * Constructs a new SwingButtonPeer. + * + * @param theButton the AWT button for this peer + */ + public SwingButtonPeer(Button theButton) + { + SwingButton button = new SwingButton(theButton); + button.setText(theButton.getLabel()); + button.addActionListener(new SwingButtonListener()); + init(theButton, button); + } + + /** + * Sets the label of the button. This call is forwarded to the setText method + * of the managed Swing button. + * + * @param label the label to set + */ + public void setLabel(String label) + { + ((SwingButton) swingComponent).setText(label); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingCanvasPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingCanvasPeer.java new file mode 100644 index 000000000..abef9ef12 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingCanvasPeer.java @@ -0,0 +1,64 @@ +/* SwingCanvasPeer.java -- A canvas peer based on Swing + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.swing; + +import java.awt.Canvas; +import java.awt.peer.CanvasPeer; +import java.awt.peer.LightweightPeer; + +/** + * A CanvasPeer to be used together with the Swing peers. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingCanvasPeer + extends SwingComponentPeer + implements LightweightPeer, CanvasPeer +{ + + /** + * Creates a new SwingCanvasPeer for the specified Canvas. + * + * @param canvas the canvas. + */ + public SwingCanvasPeer(Canvas canvas) + { + init(canvas, null); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingCheckboxPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingCheckboxPeer.java new file mode 100755 index 000000000..7080831a2 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingCheckboxPeer.java @@ -0,0 +1,256 @@ +/* SwingCheckboxPeer.java -- A Swing based peer for AWT checkboxes + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Checkbox; +import java.awt.CheckboxGroup; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.event.FocusEvent; +import java.awt.event.ItemEvent; +import java.awt.event.ItemListener; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.CheckboxPeer; + +import javax.swing.JCheckBox; +import javax.swing.JComponent; +import javax.swing.JToggleButton; + +/** + * A CheckboxPeer implementation that is backed by the Swing JCheckBox. + */ +public class SwingCheckboxPeer extends SwingComponentPeer implements + CheckboxPeer { + + /** + * A spezialized Swing checkbox used to paint the checkbox for the + * AWT checkbox. + */ + private class SwingCheckbox + extends JCheckBox + implements SwingComponent + { + Checkbox checkbox; + + SwingCheckbox(Checkbox checkbox) + { + this.checkbox = checkbox; + } + + /** + * Returns this checkbox. + * + * @return this + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to + * processMouseEvent(). + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseEvent(ev); + } + + /** + * Handles mouse motion events by forwarding it to + * processMouseMotionEvent(). + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to processKeyEvent(). + * + * @param ev the mouse event + */ + public void handleKeyEvent(KeyEvent ev) + { + ev.setSource(this); + processKeyEvent(ev); + } + + /** + * Handles focus events by forwarding it to + * processFocusEvent(). + * + * @param ev the Focus event + */ + public void handleFocusEvent(FocusEvent ev) + { + processFocusEvent(ev); + } + + /** + * Overridden so that this method returns the correct value even without a + * peer. + * + * @return the screen location of the button + */ + public Point getLocationOnScreen() + { + return SwingCheckboxPeer.this.getLocationOnScreen(); + } + + /** + * Overridden so that the isShowing method returns the correct value + * for the swing button, even if it has no peer on its own. + * + * @return true if the button is currently showing, + * false otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (checkbox != null) + retVal = checkbox.isShowing(); + return retVal; + } + + /** + * Overridden, so that the Swing button can create an Image without its + * own peer. + * + * @param w the width of the image + * @param h the height of the image + * + * @return an image + */ + public Image createImage(int w, int h) + { + return SwingCheckboxPeer.this.createImage(w, h); + } + + public Graphics getGraphics() + { + return SwingCheckboxPeer.this.getGraphics(); + } + + public Container getParent() + { + Container par = null; + if (checkbox != null) + par = checkbox.getParent(); + return par; + } + + public void requestFocus() { + SwingCheckboxPeer.this.requestFocus(awtComponent, false, true, 0); + } + + public boolean requestFocus(boolean temporary) { + return SwingCheckboxPeer.this.requestFocus(awtComponent, temporary, + true, 0); + } + } + + /** + * Listens for ActionEvents on the Swing button and triggers corresponding + * ActionEvents on the AWT button. + */ + class SwingCheckboxListener implements ItemListener + { + Checkbox awtCheckbox; + + SwingCheckboxListener(Checkbox checkbox) + { + awtCheckbox = checkbox; + } + + /** + * Receives notification when an action was performend on the button. + * + * @param event the action event + */ + public void itemStateChanged(ItemEvent event) + { + awtCheckbox.setState(event.getStateChange()==ItemEvent.SELECTED); + ItemListener[] l = awtCheckbox.getItemListeners(); + if (l.length == 0) + return; + ItemEvent ev = new ItemEvent(awtCheckbox, ItemEvent.ITEM_STATE_CHANGED, + awtCheckbox, event.getStateChange()); + for (int i = 0; i < l.length; ++i) + l[i].itemStateChanged(ev); + } + } + + /** + * Creates a new SwingCheckboxPeer instance. + */ + public SwingCheckboxPeer(Checkbox checkbox) + { + SwingCheckbox swingCheckbox = new SwingCheckbox(checkbox); + swingCheckbox.addItemListener(new SwingCheckboxListener(checkbox)); + + init(checkbox, swingCheckbox); + setLabel(checkbox.getLabel()); + setState(checkbox.getState()); + } + + public void setCheckboxGroup(CheckboxGroup group) + { + // TODO: Implement this. + } + + public void setLabel(String label) + { + ((JToggleButton) swingComponent).setText(label); + } + + public void setState(boolean state) + { + ((JToggleButton) swingComponent).setSelected(state); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java new file mode 100644 index 000000000..ca42fb748 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponent.java @@ -0,0 +1,99 @@ +/* SwingComponent.java -- An interface that defines a Swing component for peers + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; + +import javax.swing.JComponent; + +/** + * Defines some additional methods that the Swing components must implement + * in order to work with the Swing peers. This is usually achieved by + * subclassing a Swing component and forwarding the method calls to some + * protected JComponent method. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public interface SwingComponent +{ + + /** + * Returns the actual swing compenent. + * + * @return the actual swing compenent + */ + JComponent getJComponent(); + + /** + * Handles a mouse event. This is usually forwarded to + * {@link Component#processMouseMotionEvent(MouseEvent)} of the swing + * component. + * + * @param ev the mouse event + */ + void handleMouseEvent(MouseEvent ev); + + /** + * Handles a mouse motion event. This is usually forwarded to + * {@link Component#processMouseEvent(MouseEvent)} of the swing + * component. + * + * @param ev the mouse motion event + */ + void handleMouseMotionEvent(MouseEvent ev); + + /** + * Handles a key event. This is usually forwarded to + * {@link Component#processKeyEvent(KeyEvent)} of the swing + * component. + * + * @param ev the key event + */ + void handleKeyEvent(KeyEvent ev); + + /** + * Handles a focus event. This is usually forwarded to + * {@link Component#processFocusEvent(FocusEvent)} of the swing + * component. + * + * @param ev the focus event + */ + void handleFocusEvent(FocusEvent ev); +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java new file mode 100644 index 000000000..8be95dcb7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingComponentPeer.java @@ -0,0 +1,1136 @@ +/* SwingComponentPeer.java -- An abstract base class for Swing based peers + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.AWTEvent; +import java.awt.AWTException; +import java.awt.BufferCapabilities; +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Cursor; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.BufferCapabilities.FlipContents; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.PaintEvent; +import java.awt.image.ColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.image.VolatileImage; +import java.awt.peer.ComponentPeer; +import java.awt.peer.ContainerPeer; +import java.awt.peer.LightweightPeer; + +import javax.swing.JComponent; +import javax.swing.RepaintManager; + +/** + * The base class for Swing based component peers. This provides the basic + * functionality needed for Swing based component peers. Many methods are + * implemented to forward to the Swing component. Others however forward + * to the component's parent and expect the toplevel component peer to provide + * a real implementation of it. These are for example the key methods + * {@link #getGraphics()} and {@link #createImage(int, int)}, as well as + * {@link #getLocationOnScreen()}. + * + * This class also provides the necesary hooks into the Swing painting and + * event handling system. In order to achieve this, it traps paint, mouse and + * key events in {@link #handleEvent(AWTEvent)} and calls some special methods + * ({@link #peerPaint(Graphics)}, {@link #handleKeyEvent(KeyEvent)}, + * {@link #handleMouseEvent(MouseEvent)} and + * {@link #handleMouseMotionEvent(MouseEvent)}) that call the corresponding + * Swing methods. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingComponentPeer + implements ComponentPeer +{ + + /** + * The AWT component for this peer. + */ + protected Component awtComponent; + + /** + * The Swing component for this peer. + */ + protected SwingComponent swingComponent; + + /** + * The font that is set for this peer. + */ + protected Font peerFont; + + /** + * The current repaint area. + */ + protected Rectangle paintArea; + + /** + * Creates a SwingComponentPeer instance. Subclasses are expected to call + * this constructor and thereafter call {@link #init(Component, JComponent)} + * in order to setup the AWT and Swing components properly. + */ + protected SwingComponentPeer() + { + // Nothing to do here. + } + + /** + * Initializes the AWT and Swing component for this peer. It is expected that + * subclasses call this from within their constructor. + * + * @param awtComp the AWT component for this peer + * @param swingComp the Swing component for this peer + */ + protected void init(Component awtComp, SwingComponent swingComp) + { + awtComponent = awtComp; + swingComponent = swingComp; + if (swingComponent != null) + { + JComponent c = swingComponent.getJComponent(); + if (c != null) + { + c.addNotify(); + RepaintManager.currentManager(c).setDoubleBufferingEnabled(false); + System.setProperty("gnu.awt.swing.doublebuffering", "true"); + } + } + + // Register this heavyweight component with the nearest heavyweight + // container, so we get peerPaint() triggered by that container. + if (! (this instanceof LightweightPeer)) + { + Component comp = awtComponent; + Container parent = comp.getParent(); + while (parent != null && + ! (parent.getPeer() instanceof SwingContainerPeer)) + { + comp = parent; + parent = comp.getParent(); + } + + // At this point we have the ancestor with a SwingContainerPeer + // (or null peer). + if (parent != null && parent.getPeer() instanceof SwingContainerPeer) + { + SwingContainerPeer p = (SwingContainerPeer) parent.getPeer(); + p.addHeavyweightDescendent(awtComponent); + } + } + } + + /** + * Returns the construction status of the specified image. This is called + * by {@link Component#checkImage(Image, int, int, ImageObserver)}. + * + * @param img the image + * @param width the width of the image + * @param height the height of the image + * @param ob the image observer to be notified of updates of the status + * + * @return a bitwise ORed set of ImageObserver flags + */ + public int checkImage(Image img, int width, int height, ImageObserver ob) + { + return Toolkit.getDefaultToolkit().checkImage(img, width, height, ob); + } + + /** + * Creates an image by starting the specified image producer. This is called + * by {@link Component#createImage(ImageProducer)}. + * + * @param prod the image producer to be used to create the image + * + * @return the created image + */ + public Image createImage(ImageProducer prod) + { + Image image = Toolkit.getDefaultToolkit().createImage(prod); + return image; + } + + /** + * Creates an empty image with the specified width and + * height. + * + * This is implemented to let the parent component create the image. This + * eventually goes up to the top-level component peer, which is then expected + * to deliver the image. + * + * @param width the width of the image to be created + * @param height the height of the image to be created + * + * @return the created image + */ + public Image createImage(int width, int height) + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + return parentPeer.createImage(width, height); + } + + /** + * Disables the component. This is called by {@link Component#disable()}. + */ + public void disable() + { + if (swingComponent != null) + swingComponent.getJComponent().setEnabled(false); + } + + /** + * Disposes the component peer. This should release all resources held by the + * peer. This is called when the component is no longer in use. + */ + public void dispose() + { + // Unregister this heavyweight component from the nearest heavyweight + // container. + if (! (this instanceof LightweightPeer)) + { + Component comp = awtComponent; + Container parent = comp.getParent(); + while (parent != null && + ! (parent.getPeer() instanceof SwingContainerPeer)) + { + comp = parent; + parent = comp.getParent(); + } + + // At this point we have the ancestor with a SwingContainerPeer + // (or null peer). + if (parent != null && parent.getPeer() instanceof SwingContainerPeer) + { + SwingContainerPeer p = (SwingContainerPeer) parent.getPeer(); + p.removeHeavyweightDescendent(awtComponent); + } + } + + awtComponent = null; + swingComponent = null; + } + + /** + * Enables the component. This is called by {@link Component#enable()}. + */ + public void enable() + { + if (swingComponent != null) + swingComponent.getJComponent().setEnabled(true); + } + + /** + * Returns the color model of the component. This is currently not used. + * + * @return the color model of the component + */ + public ColorModel getColorModel() + { + // FIXME: When this peer method will be used, we need to provide an + // implementation of this, probably forwarding to the toplevel peer, like + // in the other methods. + return null; + } + + /** + * Returns the font metrics for the specified font. This is called by + * {@link Component#getFontMetrics(Font)}. + * + * This is implemented to query the font metrics from the parent component. + * This will eventually call the top-level component peer, which is then + * expected to deliver a font metrics object. + * + * @param f the font for which to query the font metrics + * + * @return the font metrics for the specified font + */ + public FontMetrics getFontMetrics(Font f) + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + return parentPeer.getFontMetrics(f); + } + + /** + * Returns a {@link Graphics} object suitable for drawing on this component. + * This is called by {@link Component#getGraphics()}. + * + * This is implemented to query the graphics from the parent component and + * adjust the clip and translation to match this component. + * This will eventually call the top-level component peer, which is then + * expected to deliver a graphics object. + * + * @return a graphics object suitable for drawing on this component + */ + public Graphics getGraphics() + { + Component parent = awtComponent.getParent(); + Graphics g = parent.getGraphics(); + g.translate(awtComponent.getX(), awtComponent.getY()); + g.setClip(0, 0, awtComponent.getWidth(), awtComponent.getHeight()); + return g; + } + + /** + * Returns the location of this component in screen coordinates. This is + * called by {@link Component#getLocationOnScreen()}. + * + * This is implemented to query the parent component peer for its screen + * location and adds the offset of this component to it. This will eventually + * call the top-level component's peer, which is then expected to provide + * it's screen location. + * + * @return the location of this component in screen coordinates + */ + public Point getLocationOnScreen() + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + Point location = parentPeer.getLocationOnScreen(); + location.x += awtComponent.getX(); + location.y += awtComponent.getY(); + return location; + } + + /** + * Returns the minimum size for the component. This is called by + * {@link Component#getMinimumSize()}. + * + * This is implemented to return the Swing component's minimum size. + * + * @return the minimum size for the component + */ + public Dimension getMinimumSize() + { + return minimumSize(); + } + + /** + * Returns the preferred size for the component. This is called by + * {@link Component#getPreferredSize()}. + * + * This is implemented to return the Swing component's preferred size. + * + * @return the preferred size for the component + */ + public Dimension getPreferredSize() + { + return preferredSize(); + } + + /** + * Returns the toolkit that created this peer. + * + * @return the toolkit that created this peer + */ + public Toolkit getToolkit() + { + return Toolkit.getDefaultToolkit(); + } + + /** + * Handles the given event. This is called from + * {@link Component#dispatchEvent(AWTEvent)} to give the peer a chance to + * react to events for the component. + * + * @param e the event + */ + public void handleEvent(AWTEvent e) + { + switch (e.getID()) + { + case PaintEvent.UPDATE: + case PaintEvent.PAINT: + if (awtComponent.isShowing()) + { + Rectangle clip ; + synchronized (this) + { + coalescePaintEvent((PaintEvent) e); + assert paintArea != null; + clip = paintArea; + paintArea = null; + } + Graphics g = awtComponent.getGraphics(); + try + { + g.clipRect(clip.x, clip.y, clip.width, clip.height); + peerPaint(g, e.getID() == PaintEvent.UPDATE); + } + finally + { + g.dispose(); + } + } + break; + case MouseEvent.MOUSE_PRESSED: + case MouseEvent.MOUSE_RELEASED: + case MouseEvent.MOUSE_CLICKED: + case MouseEvent.MOUSE_ENTERED: + case MouseEvent.MOUSE_EXITED: + handleMouseEvent((MouseEvent) e); + break; + case MouseEvent.MOUSE_MOVED: + case MouseEvent.MOUSE_DRAGGED: + handleMouseMotionEvent((MouseEvent) e); + break; + case KeyEvent.KEY_PRESSED: + case KeyEvent.KEY_RELEASED: + case KeyEvent.KEY_TYPED: + handleKeyEvent((KeyEvent) e); + break; + case FocusEvent.FOCUS_GAINED: + case FocusEvent.FOCUS_LOST: + handleFocusEvent((FocusEvent)e); + break; + default: + // Other event types are not handled here. + break; + } + } + + /** + * Makes the component invisible. This is called from + * {@link Component#hide()}. + * + * This is implemented to call setVisible(false) on the Swing component. + */ + public void hide() + { + if (swingComponent != null) + swingComponent.getJComponent().setVisible(false); + + Component parent = awtComponent.getParent(); + if (parent != null) + parent.repaint(awtComponent.getX(), awtComponent.getY(), + awtComponent.getWidth(), awtComponent.getHeight()); + } + + /** + * Returns true if the component can receive keyboard input + * focus. This is called from {@link Component#isFocusTraversable()}. + * + * This is implemented to return isFocusable() from the Swing component. + * + * @specnote Part of the earlier 1.1 API, replaced by isFocusable(). + */ + public boolean isFocusTraversable() + { + return swingComponent != null ? + swingComponent.getJComponent().isFocusable() : false; + } + + /** + * Returns true if the component can receive keyboard input + * focus. This is called from {@link Component#isFocusable()}. + * + * This is implemented to return isFocusable() from the Swing component. + */ + public boolean isFocusable() + { + return swingComponent != null ? + swingComponent.getJComponent().isFocusable() : false; + } + + /** + * Returns the minimum size for the component. This is called by + * {@link Component#minimumSize()}. + * + * This is implemented to return the Swing component's minimum size. + * + * @return the minimum size for the component + */ + public Dimension minimumSize() + { + Dimension retVal; + if (swingComponent != null) + retVal = swingComponent.getJComponent().getMinimumSize(); + else + retVal = new Dimension(0, 0); + return retVal; + } + + /** + * Returns the preferred size for the component. This is called by + * {@link Component#getPreferredSize()}. + * + * This is implemented to return the Swing component's preferred size. + * + * @return the preferred size for the component + */ + public Dimension preferredSize() + { + Dimension retVal; + if (swingComponent != null) + retVal = swingComponent.getJComponent().getPreferredSize(); + else + retVal = new Dimension(0, 0); + return retVal; + } + + /** + * Paints the component. This is triggered by + * {@link Component#paintAll(Graphics)}. + * + * @param graphics the graphics to paint with + */ + public void paint(Graphics graphics) + { + peerPaint(graphics, false); + } + + /** + * Prepares an image for rendering on this component. This is called by + * {@link Component#prepareImage(Image, int, int, ImageObserver)}. + * + * @param img the image to prepare + * @param width the desired width of the rendered image + * @param height the desired height of the rendered image + * @param ob the image observer to be notified of updates in the preparation + * process + * + * @return true if the image has been fully prepared, + * false otherwise (in which case the image observer + * receives updates) + */ + public boolean prepareImage(Image img, int width, int height, ImageObserver ob) + { + Component parent = awtComponent.getParent(); + if(parent != null) + { + ComponentPeer parentPeer = parent.getPeer(); + return parentPeer.prepareImage(img, width, height, ob); + } + else + { + return Toolkit.getDefaultToolkit().prepareImage(img, width, height, ob); + } + } + + public void print(Graphics graphics) + { + // FIXME: I don't know what this method is supposed to do. + } + + /** + * Repaints the specified rectangle of this component. This is called from + * {@link Component#repaint(long, int, int, int, int)}. + * + * This is implemented to call repaint() on the Swing component. + * + * @param tm number of milliseconds to wait with repainting + * @param x the X coordinate of the upper left corner of the damaged + * rectangle + * @param y the Y coordinate of the upper left corner of the damaged + * rectangle + * @param width the width of the damaged rectangle + * @param height the height of the damaged rectangle + */ + public void repaint(long tm, int x, int y, int width, int height) + { + // NOTE: This is never called by AWT but is mandated by the peer interface. + if (swingComponent != null) + swingComponent.getJComponent().repaint(tm, x, y, width, height); + else + { + PaintEvent ev = new PaintEvent(awtComponent, PaintEvent.UPDATE, + new Rectangle(x, y, width, height)); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ev); + } + } + + /** + * Requests that this component receives the focus. This is called from + * {@link Component#requestFocus()}. + * + * This calls requestFocus() on the Swing component. + * + * @specnote Part of the earlier 1.1 API, apparently replaced by argument + * form of the same method. + */ + public void requestFocus() + { + // NOTE: This is never called by AWT but is mandated by the peer interface. + Toolkit tk = Toolkit.getDefaultToolkit(); + EventQueue q = tk.getSystemEventQueue(); + q.postEvent(new FocusEvent(awtComponent, FocusEvent.FOCUS_GAINED, false)); + } + + /** + * Requests that this component receives the focus. This is called from + * {@link Component#requestFocus()}. + * + * This calls requestFocus() on the Swing component. + * + * @param source the actual component that requests focus (may be a + * lightweight descendant of the heavyweight container) + * @param tmp true when the change is temporary + * @param allowWindowFocus + * @param tm the timestamp of the focus change + * + * @return true when the focus change is guaranteed to be granted, false + * otherwise + */ + public boolean requestFocus(Component source, boolean tmp, + boolean allowWindowFocus, long tm) + { + Toolkit tk = Toolkit.getDefaultToolkit(); + EventQueue q = tk.getSystemEventQueue(); + q.postEvent(new FocusEvent(source, FocusEvent.FOCUS_GAINED, tmp)); + return true; + } + + /** + * Notifies the peer that the bounds of this component have changed. This + * is called by {@link Component#reshape(int, int, int, int)}. + * + * This is implemented to call setBounds() on the Swing component. + * + * @param x the X coordinate of the upper left corner of the component + * @param y the Y coordinate of the upper left corner of the component + * @param width the width of the component + * @param height the height of the component + */ + public void reshape(int x, int y, int width, int height) + { + if (swingComponent != null) + swingComponent.getJComponent().setBounds(x, y, width, height); + } + + /** + * Sets the background color of the component. This is called by + * {@link Component#setBackground(Color)}. + * + * This is implemented to call setBackground() on the Swing component. + * + * @param color the background color to set + */ + public void setBackground(Color color) + { + if (swingComponent != null) + swingComponent.getJComponent().setBackground(color); + } + + /** + * Notifies the peer that the bounds of this component have changed. This + * is called by {@link Component#setBounds(int, int, int, int)}. + * + * This is implemented to call setBounds() on the Swing component. + * + * @param x the X coordinate of the upper left corner of the component + * @param y the Y coordinate of the upper left corner of the component + * @param width the width of the component + * @param height the height of the component + */ + public void setBounds(int x, int y, int width, int height) + { + reshape(x, y, width, height); + } + + /** + * Sets the cursor of the component. This is called by + * {@link Component#setCursor(Cursor)}. + * + * This is implemented to call setCursor() on the Swing component. + * + * @specnote Part of the earlier 1.1 API, apparently no longer needed. + */ + public void setCursor(Cursor cursor) + { + if (swingComponent != null) + swingComponent.getJComponent().setCursor(cursor); + } + + /** + * Sets the enabled/disabled state of this component. This is called by + * {@link Component#setEnabled(boolean)}. + * + * This is implemented to call setEnabled() on the Swing component. + * + * @param enabled true to enable the component, + * false to disable it + */ + public void setEnabled(boolean enabled) + { + if (swingComponent != null) + swingComponent.getJComponent().setEnabled(enabled); + } + + /** + * Sets the font of the component. This is called by + * {@link Component#setFont(Font)}. + * + * This is implemented to call setFont() on the Swing component. + * + * @param font the font to set + */ + public void setFont(Font font) + { + peerFont = font; + if (swingComponent != null) + swingComponent.getJComponent().setFont(font); + } + + /** + * Sets the foreground color of the component. This is called by + * {@link Component#setForeground(Color)}. + * + * This is implemented to call setForeground() on the Swing component. + * + * @param color the foreground color to set + */ + public void setForeground(Color color) + { + if (swingComponent != null) + swingComponent.getJComponent().setForeground(color); + } + + /** + * Sets the visibility state of the component. This is called by + * {@link Component#setVisible(boolean)}. + * + * This is implemented to call setVisible() on the Swing component. + * + * @param visible true to make the component visible, + * false to make it invisible + */ + public void setVisible(boolean visible) + { + if (visible) + show(); + else + hide(); + } + + /** + * Makes the component visible. This is called by {@link Component#show()}. + * + * This is implemented to call setVisible(true) on the Swing component. + */ + public void show() + { + if (swingComponent != null) + swingComponent.getJComponent().setVisible(true); + } + + /** + * Get the graphics configuration of the component. The color model + * of the component can be derived from the configuration. + * + * This is implemented to return the GraphicsConfiguration of the parent + * component. This will eventually call the toplevel component peer, which + * is expected to provide a real implementation. + * + * @return the graphics configuration of the component + */ + public GraphicsConfiguration getGraphicsConfiguration() + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + return parentPeer.getGraphicsConfiguration(); + } + + /** + * Part of an older API, no longer needed. + */ + public void setEventMask(long mask) + { + // Nothing to do here. + } + + /** + * Returns true if this component has been obscured, + * false otherwise. This will only work if + * {@link #canDetermineObscurity()} also returns true. + * + * This is not yet implemented. + * + * @return true if this component has been obscured, + * false otherwise. + */ + public boolean isObscured() + { + return false; + } + + /** + * Returns true if this component peer can determine if the + * component has been obscured, false otherwise. + * + * This is not yet implemented. + * + * @return true if this component peer can determine if the + * component has been obscured, false otherwise + */ + public boolean canDetermineObscurity() + { + return false; + } + + /** + * Coalesces the specified paint event. + * + * @param e the paint event + */ + public void coalescePaintEvent(PaintEvent e) + { + synchronized (this) + { + Rectangle newRect = e.getUpdateRect(); + if (paintArea == null) + paintArea = newRect; + else + Rectangle.union(paintArea, newRect, paintArea); + } + } + + /** + * Updates the cursor. This is not yet implemented. + */ + public void updateCursorImmediately() + { + // Nothing to do here yet. + } + + /** + * Returns true, if this component can handle wheel scrolling, + * false otherwise. + * + * This is not yet implemented and returns false. + * + * @return true, if this component can handle wheel scrolling, + * false otherwise + */ + public boolean handlesWheelScrolling() + { + return false; + } + + /** + * A convenience method that creates a volatile image. The volatile + * image is created on the screen device on which this component is + * displayed, in the device's current graphics configuration. + * + * This is implemented to let the parent component peer create an image. + * This eventually ends up in the toplevel component peer, which is then + * responsible for creating the real image. + * + * @param width width of the image + * @param height height of the image + * + * @see VolatileImage + * + * @since 1.2 + */ + public VolatileImage createVolatileImage(int width, int height) + { + Component parent = awtComponent.getParent(); + VolatileImage im = null; + if (parent != null) + { + ComponentPeer parentPeer = parent.getPeer(); + im = parentPeer.createVolatileImage(width, height); + } + return im; + } + + /** + * Create a number of image buffers that implement a buffering + * strategy according to the given capabilities. + * + * This is implemented to forward to the parent component peer. Eventually + * this ends up in the top level component peer, which is then responsible + * for doing the real work. + * + * @param numBuffers the number of buffers + * @param caps the buffering capabilities + * + * @throws AWTException if the specified buffering strategy is not + * implemented + * + * @since 1.2 + */ + public void createBuffers(int numBuffers, BufferCapabilities caps) throws AWTException + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + parentPeer.createBuffers(numBuffers, caps); + } + + /** + * Return the back buffer of this component. + * + * This is implemented to forward to the parent. Eventually this ends + * up in the toplevel component, which is then responsible for providing + * a back buffer. + * + * @return the back buffer of this component. + * + * @since 1.2 + */ + public Image getBackBuffer() + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + return parentPeer.getBackBuffer(); + } + + /** + * Perform a page flip, leaving the contents of the back buffer in + * the specified state. + * + * This is implemented to forward to the parent. Eventually this ends + * up in the toplevel component, which is then responsible for doing the real + * work. + * + * @param contents the state in which to leave the back buffer + * + * @since 1.2 + */ + public void flip(FlipContents contents) + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + parentPeer.flip(contents); + } + + /** + * Destroy the resources created by createBuffers. + * + * This is implemented to forward to the parent component peer. Eventually + * this ends up in the top level component peer, which is then responsible + * for doing the real work. + * + * @since 1.2 + */ + public void destroyBuffers() + { + Component parent = awtComponent.getParent(); + ComponentPeer parentPeer = parent.getPeer(); + parentPeer.destroyBuffers(); + } + + /** + * Get the bounds of this component peer. + * + * This is implemented to forward to the Swing component. + * + * @return component peer bounds + * @since 1.5 + */ + public Rectangle getBounds() + { + Rectangle retVal; + if (swingComponent != null) + retVal = swingComponent.getJComponent().getBounds(); + else + retVal = new Rectangle(); + return retVal; + } + + /** + * Reparent this component under another container. + * + * @param parent + * @since 1.5 + */ + public void reparent(ContainerPeer parent) + { + // Nothing to do here. + } + + /** + * Set the bounds of this component peer. + * + * This is implemented to forward to the swing component. + * + * @param x the new x co-ordinate + * @param y the new y co-ordinate + * @param width the new width + * @param height the new height + * @param z the new stacking level + * @since 1.5 + */ + public void setBounds(int x, int y, int width, int height, int z) + { + if (swingComponent != null) + swingComponent.getJComponent().setBounds(x, y, width, height); + // FIXME: Somehow handle the Z order. + } + + /** + * Check if this component supports being reparented. + * + * @return true if this component can be reparented, + * false otherwise. + * @since 1.5 + */ + public boolean isReparentSupported() + { + return true; + } + + + /** + * Layout this component peer. + * + * @since 1.5 + */ + public void layout() + { + if (swingComponent != null) + swingComponent.getJComponent().doLayout(); + } + + /** + * Triggers 'heavyweight' painting of the components. This usually calls + * paint() on the Swing component. + * + * @param g the graphics context to use for painting + * @param update wether we need to call update or paint on the AWT component + */ + protected void peerPaint(Graphics g, boolean update) + { + peerPaintComponent(g); + + Graphics userGraphics = g.create(); + try{ + if (update) + awtComponent.update(userGraphics); + else + awtComponent.paint(userGraphics); + } finally { + userGraphics.dispose(); + } + + } + + /** + * Paints the actual 'heavyweight' swing component, if there is one + * associated to this peer. + * + * @param g the graphics to paint the component with + */ + protected void peerPaintComponent(Graphics g) + { + // Paint the actual Swing component if this peer has one. + if (swingComponent != null) + swingComponent.getJComponent().paint(g); + } + + /** + * Handles mouse events on the component. This is usually forwarded to the + * SwingComponent's processMouseEvent() method. + * + * @param e the mouse event + */ + protected void handleMouseEvent(MouseEvent e) + { + if (swingComponent != null) + swingComponent.handleMouseEvent(e); + } + + /** + * Handles mouse motion events on the component. This is usually forwarded + * to the SwingComponent's processMouseMotionEvent() method. + * + * @param e the mouse motion event + */ + protected void handleMouseMotionEvent(MouseEvent e) + { + if (swingComponent != null) + swingComponent.handleMouseMotionEvent(e); + } + + /** + * Handles key events on the component. This is usually forwarded to the + * SwingComponent's processKeyEvent() method. + * + * @param e the key event + */ + protected void handleKeyEvent(KeyEvent e) + { + if (swingComponent != null) + swingComponent.handleKeyEvent(e); + } + + /** + * Handles focus events on the component. This is usually forwarded to the + * SwingComponent's processFocusEvent() method. + * + * @param e the key event + */ + protected void handleFocusEvent(FocusEvent e) + { + if (swingComponent != null) + swingComponent.handleFocusEvent(e); + } + + + /** + * Returns the AWT component for this peer. + * + * @return the AWT component for this peer + */ + public Component getComponent() + { + return awtComponent; + } + + public boolean requestFocus(Component lightweightChild, boolean temporary, + boolean focusedWindowChangeAllowed, + long time, sun.awt.CausedFocusEvent.Cause cause) + { + return true; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java new file mode 100644 index 000000000..ca3adc4c7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingContainerPeer.java @@ -0,0 +1,378 @@ +/* SwingContainerPeer.java -- A Swing based peer for AWT containers + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import gnu.classpath.SystemProperties; + +import java.awt.Component; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.ComponentPeer; +import java.awt.peer.ContainerPeer; +import java.util.Iterator; +import java.util.LinkedList; + +/** + * A peer for Container to be used with the Swing based AWT peers. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingContainerPeer + extends SwingComponentPeer + implements ContainerPeer +{ + + /** + * Stores all heavyweight descendents of the container. This is used + * in {@link #peerPaintChildren(Graphics)}. + */ + private LinkedList heavyweightDescendents; + + /** + * The backbuffer used for painting UPDATE events. + */ + private Image backbuffer; + + /** + * Creates a new SwingContainerPeer. + * + * @param awtCont + */ + public SwingContainerPeer(Container awtCont) + { + heavyweightDescendents = new LinkedList(); + } + + /** + * Registers a heavyweight descendent. This is then painted by + * {@link #peerPaintChildren(Graphics)}. + * + * @param comp the descendent to register + * + * @see #peerPaintChildren(Graphics) + * @see #removeHeavyweightDescendent(Component) + */ + protected synchronized void addHeavyweightDescendent(Component comp) + { + heavyweightDescendents.add(comp); + focusOwner = null; + } + + /** + * Unregisters a heavyweight descendent. + * + * @param comp the descendent to unregister + * + * @see #peerPaintChildren(Graphics) + * @see #addHeavyweightDescendent(Component) + */ + protected synchronized void removeHeavyweightDescendent(Component comp) + { + heavyweightDescendents.remove(comp); + focusOwner = null; + } + + /** + * Returns an array of all registered heavyweight descendents. + * + * @return all registered heavyweight descendents + */ + protected Component[] getHeavyweightDescendents() + { + Component[] heavyweights = new Component[heavyweightDescendents.size()]; + heavyweights = (Component[]) heavyweightDescendents.toArray(heavyweights); + return heavyweights; + } + + /** + * Returns the insets of the container. + * + * This is implemented to return the insets of the Swing container. + * + * @return the insets of the container + */ + public Insets insets() + { + Insets retVal; + if (swingComponent != null) + retVal = swingComponent.getJComponent().getInsets(); + else + retVal = new Insets(0, 0, 0, 0); + return retVal; + } + + /** + * Returns the insets of the container. + * + * This is implemented to return the insets of the Swing container. + * + * @return the insets of the container + */ + public Insets getInsets() + { + return insets(); + } + + /** + * Called before the validation of this containers begins. + */ + public void beginValidate() + { + // Nothing to do here. + } + + /** + * Called after the validation of this containers ended. + */ + public void endValidate() + { + // Nothing to do here. + } + + /** + * Called before the layout of this containers begins. + */ + public void beginLayout() + { + // Nothing to do here. + } + + /** + * Called after the layout of this containers ended. + */ + public void endLayout() + { + // Nothing to do here. + } + + /** + * Returns false unconditionally. This method is not used at + * the moment. + * + * @return false + */ + public boolean isPaintPending() + { + return false; + } + + /** + * Returns false unconditionally. This method is not used at + * the moment. + * + * @return false + */ + public boolean isRestackSupported() + { + return false; + } + + /** + * This method is not used at the moment. + */ + public void cancelPendingPaint(int x, int y, int width, int height) + { + // Nothing to do here. + } + + /** + * This method is not used at the moment. + */ + public void restack() + { + // Nothing to do here. + } + + /** + * Performs the super behaviour (call peerPaintComponent() and + * awtComponent.paint()), and forwards the paint request to the heavyweight + * descendents of the container. + */ + protected void peerPaint(Graphics g, boolean update) + { + if (isDoubleBuffering()) + { + int width = awtComponent.getWidth(); + int height = awtComponent.getHeight(); + if (backbuffer == null + || backbuffer.getWidth(awtComponent) < width + || backbuffer.getHeight(awtComponent) < height) + backbuffer = awtComponent.createImage(width, height); + Graphics g2 = backbuffer.getGraphics(); + Rectangle clip = g.getClipRect(); + try + { + g2.setClip(clip); + super.peerPaint(g2, update); + peerPaintChildren(g2); + } + finally + { + g2.dispose(); + } + g.drawImage(backbuffer, 0, 0, awtComponent); + } + else + { + super.peerPaint(g, update); + peerPaintChildren(g); + } + } + + /** + * Determines if we should do double buffering or not. + * + * @return if we should do double buffering or not + */ + private boolean isDoubleBuffering() + { + Object prop = + SystemProperties.getProperty("gnu.awt.swing.doublebuffering", "false"); + return prop.equals("true"); + } + + /** + * Paints any heavyweight child components. + * + * @param g the graphics to use for painting + */ + protected synchronized void peerPaintChildren(Graphics g) + { + // TODO: Is this the right painting order? + for (Iterator i = heavyweightDescendents.iterator(); i.hasNext();) + { + Component child = (Component) i.next(); + ComponentPeer peer = child.getPeer(); + + if (peer instanceof SwingComponentPeer && child.isVisible()) + { + // TODO: The translation here doesn't work for deeper + // nested children. Fix this! + Graphics g2 = g.create(child.getX(), child.getY(), + child.getWidth(), child.getHeight()); + try + { + // update() is only called for the topmost component if + // necessary, all other components only get paint() called. + ((SwingComponentPeer) peer).peerPaint(g2, false); + } + finally + { + g2.dispose(); + } + } + } + } + + /** + * Handles mouse events by dispatching it to the correct component. + * + * @param ev the mouse event + */ + protected void handleMouseEvent(MouseEvent ev) + { + Component comp = awtComponent.getComponentAt(ev.getPoint()); + if(comp == null) comp = awtComponent; + ComponentPeer peer = comp.getPeer(); + if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer) + { + ev.translatePoint(comp.getX(), comp.getY()); + ev.setSource(comp); + ((SwingComponentPeer) peer).handleMouseEvent(ev); + } + } + + /** + * Handles mouse events by dispatching it to the correct component. + * + * @param ev the mouse event + */ + protected void handleMouseMotionEvent(MouseEvent ev) + { + Component comp = awtComponent.getComponentAt(ev.getPoint()); + if (comp != null) + { + ComponentPeer peer = comp.getPeer(); + if (awtComponent != comp && !comp.isLightweight() && peer instanceof SwingComponentPeer) + { + ev.translatePoint(comp.getX(), comp.getY()); + ((SwingComponentPeer) peer).handleMouseMotionEvent(ev); + } + } + } + + /** + * Handles key events on the component. This is usually forwarded to the + * SwingComponent's processKeyEvent() method. + * + * @param e the key event + */ + protected void handleKeyEvent(KeyEvent e) + { + Component owner = getFocusOwner(); + if(owner != null) + owner.getPeer().handleEvent(e); + else + super.handleKeyEvent(e); + } + + private Component focusOwner = null; + + private Component getFocusOwner() + { + if(focusOwner == null) + { + for(Iterator iter=heavyweightDescendents.iterator(); iter.hasNext();) + { + Component child = (Component) iter.next(); + if(child.isFocusable()) + { + focusOwner = child; + break; + } + } + } + return focusOwner; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java new file mode 100644 index 000000000..56c7417cd --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingFramePeer.java @@ -0,0 +1,197 @@ +/* SwingFramePeer.java -- An abstract Swing based peer for AWT frames + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.MenuBar; +import java.awt.Point; +import java.awt.event.MouseEvent; +import java.awt.peer.ComponentPeer; +import java.awt.peer.FramePeer; + +/** + * An abstract base class for FramePeer implementations based on Swing. + * This class provides the ability to display and handle AWT MenuBars that + * are based on Swing. + * + * As a minimum, a subclass must implement all the remaining abstract methods + * as well as the following methods: + *
    + *
  • {@link ComponentPeer#getLocationOnScreen()}
  • + *
  • {@link ComponentPeer#getGraphics()}
  • + *
  • {@link ComponentPeer#createImage(int, int)}
  • + *
+ * + * @author Roman Kennke (kennke@aicas.com) + */ +public abstract class SwingFramePeer + extends SwingWindowPeer + implements FramePeer +{ + /** + * The menu bar to display. + */ + SwingMenuBarPeer menuBar = null; + + /** + * Creates a new SwingFramePeer. + * + * @param frame the frame + */ + public SwingFramePeer(Frame frame) + { + super(frame); + } + + /** + * Sets the menu bar to display in this frame. + * + * @param mb the menu bar to set + */ + public void setMenuBar(MenuBar mb) + { + menuBar = (SwingMenuBarPeer) mb.getPeer(); + menuBar.setFramePeer(this); + menuBar.setWidth(awtComponent.getWidth()); + } + + /** + * Triggers 'heavyweight' painting of the frame. This will paint a menu bar + * if present as well as the child components of this frame. + * + * @param g the graphics context to use for painting + */ + protected void peerPaintComponent(Graphics g) + { + super.peerPaintComponent(g); + if (menuBar != null) + menuBar.peerPaint(g); + } + + /** + * Sets the size and location of this frame. This resizes the menubar to fit + * within the frame. + * + * @param x the X coordinate of the screen location + * @param y the Y coordinate of the screen location + * @param w the width of the frame + * @param h the height of the frame + */ + public void setBounds(int x, int y, int w, int h) + { + super.setBounds(x, y, w, h); + if (menuBar != null) + menuBar.setWidth(w); + } + + /** + * Calculates the insets of this frame peer. This fetches the insets + * from the superclass and adds the insets of the menubar if one is present. + * + * @return the insets of the frame + */ + public Insets getInsets() + { + Insets insets = super.getInsets(); + if (menuBar != null) + insets.top += menuBar.getHeight(); + return insets; + } + + /** + * Returns the location of the menu on the screen. This is needed internally + * by the {@link SwingMenuBarPeer} in order to determine its screen location. + * + * @return the location of the menu on the screen + */ + public Point getMenuLocationOnScreen() + { + Insets i = super.getInsets(); + return new Point(i.top, i.left); + } + + /** + * Overridden to provide the ability to handle menus. + * + * @param ev the mouse event + */ + protected void handleMouseEvent(MouseEvent ev) + { + Point p = ev.getPoint(); + Insets i = super.getInsets(); + if (menuBar != null) + { + int menuHeight = menuBar.getHeight(); + if (p.y >= i.top && p.y <= i.top + menuHeight) + menuBar.handleMouseEvent(ev); + else + { + ev.translatePoint(0, -menuHeight); + super.handleMouseMotionEvent(ev); + } + } + + super.handleMouseEvent(ev); + } + + /** + * Overridden to provide the ability to handle menus. + * + * @param ev the mouse event + */ + protected void handleMouseMotionEvent(MouseEvent ev) + { + Point p = ev.getPoint(); + Insets i = super.getInsets(); + if (menuBar != null) + { + int menuHeight = menuBar.getHeight(); + if (p.y >= i.top && p.y <= i.top + menuHeight) + menuBar.handleMouseMotionEvent(ev); + else + { + ev.translatePoint(0, -menuHeight); + super.handleMouseMotionEvent(ev); + } + } + + super.handleMouseMotionEvent(ev); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingLabelPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingLabelPeer.java new file mode 100644 index 000000000..5c979d613 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingLabelPeer.java @@ -0,0 +1,242 @@ +/* SwingLabelPeer.java -- A Swing based peer for AWT labels + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Label; +import java.awt.Point; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.LabelPeer; + +import javax.swing.JComponent; +import javax.swing.JLabel; + + +/** + * A Label peer based on {@link JLabel}. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingLabelPeer + extends SwingComponentPeer + implements LabelPeer +{ + + /** + * A spezialized Swing label used to paint the label for the AWT Label. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingLabel + extends JLabel + implements SwingComponent + { + Label label; + + + SwingLabel(Label label) + { + this.label = label; + } + + /** + * Returns this label. + * + * @return this + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to + * processMouseEvent(). + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + processMouseEvent(ev); + } + + /** + * Handles mouse motion events by forwarding it to + * processMouseMotionEvent(). + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to processKeyEvent(). + * + * @param ev the mouse event + */ + public void handleKeyEvent(KeyEvent ev) + { + processKeyEvent(ev); + } + + /** + * Handles focus events by forwarding it to + * processFocusEvent(). + * + * @param ev the Focus event + */ + public void handleFocusEvent(FocusEvent ev) + { + processFocusEvent(ev); + } + + /** + * Overridden so that this method returns the correct value even without a + * peer. + * + * @return the screen location of the button + */ + public Point getLocationOnScreen() + { + return SwingLabelPeer.this.getLocationOnScreen(); + } + + /** + * Overridden so that the isShowing method returns the correct value for the + * swing button, even if it has no peer on its own. + * + * @return true if the button is currently showing, + * false otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (label != null) + retVal = label.isShowing(); + return retVal; + } + + /** + * Overridden, so that the Swing button can create an Image without its + * own peer. + * + * @param w the width of the image + * @param h the height of the image + * + * @return an image + */ + public Image createImage(int w, int h) + { + return SwingLabelPeer.this.createImage(w, h); + } + + public Graphics getGraphics() + { + return SwingLabelPeer.this.getGraphics(); + } + + public Container getParent() + { + Container par = null; + if (label != null) + par = label.getParent(); + return par; + } + } + + /** + * Creates a new SwingLabelPeer for the specified AWT label. + * + * @param label the AWT label + */ + public SwingLabelPeer(Label label) + { + super(); + SwingLabel swingLabel = new SwingLabel(label); + swingLabel.setText(label.getText()); + swingLabel.setOpaque(true); + init(label, swingLabel); + setAlignment(label.getAlignment()); + } + + /** + * Sets the text of the label. This is implemented to set the text on the + * Swing label. + * + * @param text the text to be set + */ + public void setText(String text) + { + ((JLabel) swingComponent.getJComponent()).setText(text); + } + + /** + * Sets the horizontal alignment of the label. This is implemented to + * set the alignment on the Swing label. + * + * @param alignment the horizontal alignment + * + * @see Label#LEFT + * @see Label#RIGHT + * @see Label#CENTER + */ + public void setAlignment(int alignment) + { + JLabel swingLabel = (JLabel) swingComponent.getJComponent(); + switch (alignment) + { + case Label.RIGHT: + swingLabel.setHorizontalAlignment(JLabel.RIGHT); + break; + case Label.CENTER: + swingLabel.setHorizontalAlignment(JLabel.CENTER); + break; + case Label.LEFT: + default: + swingLabel.setHorizontalAlignment(JLabel.LEFT); + break; + } + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingListPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingListPeer.java new file mode 100644 index 000000000..cf766fd4f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingListPeer.java @@ -0,0 +1,364 @@ +/* SwingListPeer.java -- A Swing based peer for AWT lists + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Color; +import java.awt.Component; +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.List; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.peer.ListPeer; + +import javax.swing.DefaultListModel; +import javax.swing.JComponent; +import javax.swing.JList; +import javax.swing.JScrollPane; +import javax.swing.ListSelectionModel; + +public class SwingListPeer + extends SwingComponentPeer + implements ListPeer +{ + + /** + * A spezialized Swing scroller used to hold the list. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingList + extends JScrollPane + implements SwingComponent + { + + SwingList(Component comp) + { + super(comp, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + } + + /** + * Returns this label. + * + * @return this + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to + * processMouseEvent(). + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + dispatchEvent(ev); + } + + /** + * Force lightweight mouse dispatching. + */ + public boolean isLightweight() + { + return false; + } + + /** + * Handles mouse motion events by forwarding it to + * processMouseMotionEvent(). + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to processKeyEvent(). + * + * @param ev the mouse event + */ + public void handleKeyEvent(KeyEvent ev) + { + processKeyEvent(ev); + } + + /** + * Handles focus events by forwarding it to processFocusEvent(). + * + * @param ev the Focus event + */ + public void handleFocusEvent(FocusEvent ev) + { + processFocusEvent(ev); + } + + + /** + * Overridden so that this method returns the correct value even without a + * peer. + * + * @return the screen location of the button + */ + public Point getLocationOnScreen() + { + return SwingListPeer.this.getLocationOnScreen(); + } + + /** + * Overridden so that the isShowing method returns the correct value for the + * swing button, even if it has no peer on its own. + * + * @return true if the button is currently showing, + * false otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (SwingListPeer.this.awtComponent != null) + retVal = SwingListPeer.this.awtComponent.isShowing(); + return retVal; + } + + /** + * Overridden, so that the Swing button can create an Image without its + * own peer. + * + * @param w the width of the image + * @param h the height of the image + * + * @return an image + */ + public Image createImage(int w, int h) + { + return SwingListPeer.this.createImage(w, h); + } + + public Graphics getGraphics() + { + return SwingListPeer.this.getGraphics(); + } + + public Container getParent() + { + Container par = null; + if (SwingListPeer.this.awtComponent != null) + par = SwingListPeer.this.awtComponent.getParent(); + return par; + } + } + + /** + * The actual Swing JList. + */ + private JList jList; + + private DefaultListModel listModel; + + public SwingListPeer(List list) + { + super(); + listModel = new DefaultListModel(); + jList = new JList(listModel); + SwingList swingList = new SwingList(jList); + init(list, swingList); + + // Pull over the items from the list. + String[] items = list.getItems(); + for (int i = 0 ; i < items.length; i++) + addItem(items[i], i); + } + + public void add(String item, int index) + { + if (listModel != null) + listModel.add(index, item); + } + + public void addItem(String item, int index) + { + if (listModel != null) + listModel.add(index, item); + } + + public void clear() + { + if (listModel != null) + listModel.clear(); + } + + public void delItems(int startIndex, int endIndex) + { + if (listModel != null) + listModel.removeRange(startIndex, endIndex); + } + + public void deselect(int index) + { + if (jList != null) + { + jList.getSelectionModel().removeSelectionInterval(index, index); + } + } + + public Dimension getMinimumSize(int s) + { + Dimension d = null; + if (jList != null) + { + d = jList.getComponent(s).getMinimumSize(); + } + return d; + } + + public Dimension getPreferredSize(int s) + { + Dimension d = null; + if (jList != null) + { + d = jList.getComponent(s).getPreferredSize(); + } + return d; + } + + public int[] getSelectedIndexes() + { + int[] sel = null; + if (jList != null) + { + sel = jList.getSelectedIndices(); + } + return sel; + } + + public void makeVisible(int index) + { + if (jList != null) + { + Component comp = jList.getComponent(index); + jList.scrollRectToVisible(comp.getBounds()); + } + } + + public Dimension minimumSize(int s) + { + Dimension d = null; + if (jList != null) + { + d = jList.getComponent(s).getMinimumSize(); + } + return d; + } + + public Dimension preferredSize(int s) + { + Dimension d = null; + if (jList != null) + { + d = jList.getComponent(s).getPreferredSize(); + } + return d; + } + + public void removeAll() + { + if (jList != null) + { + jList.removeAll(); + } + } + + public void select(int index) + { + if (jList != null) + { + jList.setSelectedIndex(index); + } + } + + public void setMultipleMode(boolean multi) + { + if (jList != null) + { + jList.setSelectionMode(multi + ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION + : ListSelectionModel.SINGLE_SELECTION); + } + } + + public void setMultipleSelections(boolean multi) + { + if (jList != null) + { + jList.setSelectionMode(multi + ? ListSelectionModel.MULTIPLE_INTERVAL_SELECTION + : ListSelectionModel.SINGLE_SELECTION); + } + } + + public void reshape(int x, int y, int width, int height) + { + if (swingComponent != null) + { + swingComponent.getJComponent().setBounds(x, y, width, height); + swingComponent.getJComponent().validate(); + } + } + + protected void peerPaint(Graphics g, boolean update) + { + super.peerPaint(g, update); + jList.doLayout(); + jList.list(); + + Rectangle r = getBounds(); + g.setColor(Color.RED); + g.drawRect(r.x, r.y, r.width, r.height); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java new file mode 100644 index 000000000..0033efb02 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuBarPeer.java @@ -0,0 +1,295 @@ +/* SwingMenuBarPeer.java -- A Swing based peer for AWT menu bars + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Container; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.Point; +import java.awt.event.MouseEvent; +import java.awt.peer.MenuBarPeer; + +import javax.swing.JMenuBar; + +/** + * A Swing based peer for the AWT menu bar. This is a little bit different from + * the other peers, since the AWT MenuBar is not derived from the AWT + * component. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingMenuBarPeer + implements MenuBarPeer +{ + + /** + * The AWT menu bar. + */ + MenuBar awtMenuBar; + + /** + * The Swing menu bar. + */ + SwingMenuBar menuBar; + + /** + * The peer of the frame that contains this menu bar. + */ + SwingFramePeer framePeer; + + /** + * A specialized JMenuBar that can be used as 'backend' for AWT MenuBars. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingMenuBar + extends JMenuBar + { + /** + * Overridden in order to provide a parent frame for this menu bar. The + * menu bar still is not inside the component hierarchy, we are faking + * here. + */ + public Container getParent() + { + Container result = null; + if (framePeer != null) + result = (Container) framePeer.awtComponent; + return result; + } + + /** + * Unconditionally returns true, since we assume that when the + * menubar has a peer, it must be showing. + * + * @return true + */ + public boolean isShowing() + { + // FIXME: This might be wrong. Maybe find a better way to do that. + return true; + } + + /** + * Handles mouse events by forwarding it to + * processMouseEvent(). + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseEvent(ev); + } + + /** + * Determines the menubar's screen location by asking the SwingFramePeer + * for it. + * + * @return the screen location of the menu bar + */ + public Point getLocationOnScreen() + { + return framePeer.getMenuLocationOnScreen(); + } + } + + /** + * Creates a new SwingMenuBarPeer instance. + * + * @param awtMenuBar the AWT menu bar + */ + public SwingMenuBarPeer(MenuBar awtMenuBar) + { + this.awtMenuBar = awtMenuBar; + menuBar = new SwingMenuBar(); + menuBar.setDoubleBuffered(false); + // Add all the menus that are already in the MenuBar. + for (int i = 0; i < awtMenuBar.getMenuCount(); i++) + { + Menu menu = awtMenuBar.getMenu(i); + menu.addNotify(); + addMenu(awtMenuBar.getMenu(i)); + } + } + + /** + * Sets the SwingFramePeer of the frame that holds this menu. + * + * @param peer the SwingFramePeer to set + */ + public void setFramePeer(SwingFramePeer peer) + { + framePeer = peer; + } + + /** + * Adds a menu to the menu bar. + * + * @param m the menu to add + */ + public void addMenu(Menu m) + { + SwingMenuPeer menuPeer = (SwingMenuPeer) m.getPeer(); + menuBar.add(menuPeer.menu); + } + + /** + * Adds a help menu to the menu bar. + * + * @param menu the menu to add + */ + public void addHelpMenu(Menu menu) + { + // FIXME: We should manage the help menu differently, so that it always + // appears at the rightmost position. + SwingMenuPeer menuPeer = (SwingMenuPeer) menu.getPeer(); + menuBar.add(menuPeer.menu); + } + + /** + * Removes the menu with the specified index. + * + * @param index the index of the menu to remove + */ + public void delMenu(int index) + { + menuBar.remove(index); + } + + /** + * Disposes this peer. This releases any reference to the AWT and Swing + * components. + */ + public void dispose() + { + menuBar = null; + awtMenuBar = null; + } + + /** + * Sets a font for the menu bar. + * + * @param font the font to set + */ + public void setFont(Font font) + { + menuBar.setFont(font); + } + + /** + * Sets the width of the menu bar. This is called from the top level + * component peers to adjust the width of the menubar when their sizes + * change. + * + * @param w the width to set + */ + public void setWidth(int w) + { + menuBar.setSize(w, menuBar.getPreferredSize().height); + menuBar.doLayout(); + } + + /** + * Paints the menu bar. + * + * @param g the graphics context to use for painting + */ + public void peerPaint(Graphics g) + { + menuBar.paint(g); + } + + /** + * Determines the height of the menubar. + * + * @return the height of the menu bar + */ + public int getHeight() + { + return menuBar.getPreferredSize().height; + } + + /** + * Handles mouse events. + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + Point point = ev.getPoint(); + for (int i = 0; i < awtMenuBar.getMenuCount(); i++) + { + Menu menu = awtMenuBar.getMenu(i); + SwingMenuPeer peer = (SwingMenuPeer) menu.getPeer(); + int x1 = peer.getX(); + int x2 = x1 + peer.getWidth(); + if (point.x >= x1 && point.x <= x2) + { + ev.translatePoint(peer.getX(), peer.getY()); + peer.handleMouseEvent(ev); + break; + } + } + } + + /** + * Handles mouse motion events. + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + Point point = ev.getPoint(); + for (int i = 0; i < awtMenuBar.getMenuCount(); i++) + { + Menu menu = awtMenuBar.getMenu(i); + SwingMenuPeer peer = (SwingMenuPeer) menu.getPeer(); + int x1 = peer.getX(); + int x2 = x1 + peer.getWidth(); + if (point.x >= x1 && point.x <= x2) + { + ev.translatePoint(peer.getX(), peer.getY()); + peer.handleMouseMotionEvent(ev); + break; + } + } + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuItemPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuItemPeer.java new file mode 100644 index 000000000..721b3349f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuItemPeer.java @@ -0,0 +1,157 @@ +/* SwingMenuItemPeer.java -- A Swing based peer for AWT menu items + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Font; +import java.awt.MenuItem; +import java.awt.Toolkit; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.peer.MenuItemPeer; + +import javax.swing.JMenuItem; + +/** + * A Swing based peer for the AWT MenuItem. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingMenuItemPeer + implements MenuItemPeer +{ + /** + * The AWT menu item. + */ + MenuItem awtMenuItem; + + /** + * The Swing menu item. + */ + JMenuItem menuItem; + + /** + * Receives ActionEvents from the Swing menu item and forwards them + * to the ActionListeners of the AWT MenuItem. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingMenuItemListener implements ActionListener + { + + /** + * Receives notification when the action has been performed. + * + * @param event the action event + */ + public void actionPerformed(ActionEvent event) + { + event.setSource(awtMenuItem); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(event); + } + + } + + /** + * Creates a new instance of SwingMenuItemPeer. + * + * @param awtMenuItem the AWT menu item + */ + public SwingMenuItemPeer(MenuItem awtMenuItem) + { + this.awtMenuItem = awtMenuItem; + menuItem = new JMenuItem(awtMenuItem.getLabel()); + menuItem.addActionListener(new SwingMenuItemListener()); + } + + /** + * Disables the menu item. + */ + public void disable() + { + menuItem.setEnabled(false); + } + + /** + * Enables the menu item. + */ + public void enable() + { + menuItem.setEnabled(true); + } + + /** + * Sets the enabled state to enabled. + * + * @param enabled if the menu item should be enabled or not + */ + public void setEnabled(boolean enabled) + { + menuItem.setEnabled(enabled); + } + + /** + * Sets the label for the menu item. + * + * @param text the label to set + */ + public void setLabel(String text) + { + menuItem.setText(text); + } + + /** + * Disposes the menu item. This releases any reference to the Swing and AWT + * menu item. + */ + public void dispose() + { + menuItem = null; + awtMenuItem = null; + } + + /** + * Sets the font for this menu item. + * + * @param font the font to set + */ + public void setFont(Font font) + { + menuItem.setFont(font); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuPeer.java new file mode 100644 index 000000000..afe20616d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingMenuPeer.java @@ -0,0 +1,284 @@ +/* SwingMenuPeer.java -- A Swing based peer for AWT menus + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Font; +import java.awt.Menu; +import java.awt.MenuItem; +import java.awt.Point; +import java.awt.event.MouseEvent; +import java.awt.peer.MenuPeer; + +import javax.swing.JMenu; + +/** + * A Swing based peer for the AWT menu. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingMenuPeer + implements MenuPeer +{ + + /** + * The AWT menu. + */ + Menu awtMenu; + + /** + * The Swing menu. + */ + SwingMenu menu; + + /** + * A specialized JMenu that can be used as 'backend' for an AWT menu. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingMenu + extends JMenu + { + + /** + * Unconditionally returns true, since we assume that when the + * menu has a peer, it must be showing. + * + * @return true + */ + public boolean isShowing() + { + // FIXME: This might be wrong. Maybe find a better way to do that. + return true; + } + + /** + * Overridden so that we can provide a location even without a real peer + * attached. + * + * @return the screen location of this menu + */ + public Point getLocationOnScreen() + { + Point parentLoc = getParent().getLocationOnScreen(); + parentLoc.x += getX(); + parentLoc.y += getY(); + return parentLoc; + } + + /** + * Handles mouse events by forwarding them to + * processMouseEvent(). + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseEvent(ev); + } + + /** + * Handles mouse events by forwarding them to + * processMouseMotionEvent(). + * + * @param ev the mouse event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseMotionEvent(ev); + } + } + + /** + * Creates a new SwingMenuPeer instance. + * + * @param awtMenu the AWT menu + */ + public SwingMenuPeer(Menu awtMenu) + { + this.awtMenu = awtMenu; + menu = new SwingMenu(); + menu.setDoubleBuffered(false); + menu.setText(awtMenu.getLabel()); + for (int i = 0; i < awtMenu.getItemCount(); i++) + { + MenuItem item = awtMenu.getItem(i); + item.addNotify(); + SwingMenuItemPeer peer = (SwingMenuItemPeer) item.getPeer(); + menu.add(peer.menuItem); + } + } + + /** + * Adds a menu item to this menu. + * + * @param item the menu item to add + */ + public void addItem(MenuItem item) + { + SwingMenuItemPeer menuItemPeer = (SwingMenuItemPeer) item.getPeer(); + menu.add(menuItemPeer.menuItem); + } + + /** + * Adds a separator to the menu. + */ + public void addSeparator() + { + menu.addSeparator(); + } + + /** + * Removes a menu item from the menu. + * + * @param index the index of the menu item to remove + */ + public void delItem(int index) + { + menu.remove(index); + } + + /** + * Disables the menu. + */ + public void disable() + { + menu.setEnabled(false); + } + + /** + * Enables the menu. + */ + public void enable() + { + menu.setEnabled(true); + } + + /** + * Sets the enabled state of the menu to enabled. + * + * @param enabled if the menu should be enabled or not + */ + public void setEnabled(boolean enabled) + { + menu.setEnabled(enabled); + } + + /** + * Sets the label of the menu. + * + * @param text the label to set + */ + public void setLabel(String text) + { + menu.setText(text); + } + + /** + * Releases any reference to the AWT and Swing menu instances. + */ + public void dispose() + { + menu = null; + awtMenu = null; + } + + /** + * Sets the font for the menu. + * + * @param font the font to set + */ + public void setFont(Font font) + { + menu.setFont(font); + } + + /** + * Handles mouse events by forwarding them to the Swing menu. + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + menu.handleMouseEvent(ev); + } + + /** + * Handles mouse motion events by forwarding them to the Swing menu. + * + * @param ev the mouse event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + menu.handleMouseMotionEvent(ev); + } + + /** + * Returns the X coordinate of the upper left corner of the menu. This is + * used internally by the SwingMenuBarPeer. + * + * @return the X coordinate of the upper left corner of the menu + */ + int getX() + { + return menu.getX(); + } + + /** + * Returns the width of the menu. This is used internally by the + * SwingMenuBarPeer. + * + * @return the X coordinate of the upper left corner of the menu + */ + int getWidth() + { + return menu.getWidth(); + } + + /** + * Returns the Y coordinate of the upper left corner of the menu. This is + * used internally by the SwingMenuBarPeer. + * + * @return the X coordinate of the upper left corner of the menu + */ + public int getY() + { + return menu.getY(); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingPanelPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingPanelPeer.java new file mode 100644 index 000000000..37c6dbc7a --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingPanelPeer.java @@ -0,0 +1,67 @@ +/* SwingPanelPeer.java -- A PanelPeer based on Swing + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.swing; + +import java.awt.Panel; +import java.awt.peer.PanelPeer; + +/** + * A panel peer based on Swing. + * + * @author Roman Kennke (kennke@aicas.com) + */ +// TODO: Maybe base implementation on JPanel. However, this doesn't seem +// necessary, but might be good for more consistent Look. +public class SwingPanelPeer + extends SwingContainerPeer + implements PanelPeer +{ + + /** + * Creates a new instance of SwingPanelPeer for the specified + * AWT panel. + * + * @param panel the AWT panel + */ + public SwingPanelPeer(Panel panel) + { + super(panel); + init(panel, null); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingTextAreaPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingTextAreaPeer.java new file mode 100644 index 000000000..d56e950ec --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingTextAreaPeer.java @@ -0,0 +1,487 @@ +/* SwingTextAreaPeer.java -- A Swing based peer for AWT textareas + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.TextArea; +import java.awt.event.ComponentEvent; +import java.awt.event.FocusEvent; +import java.awt.event.HierarchyEvent; +import java.awt.event.InputMethodEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.MouseWheelEvent; +import java.awt.im.InputMethodRequests; +import java.awt.peer.TextAreaPeer; + +import javax.swing.JComponent; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import javax.swing.JViewport; +import javax.swing.text.BadLocationException; + +public class SwingTextAreaPeer + extends SwingComponentPeer + implements TextAreaPeer +{ + + /** + * A spezialized Swing scroller used to hold the textarea. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingScrollPane + extends JScrollPane + implements SwingComponent + { + + SwingTextArea textArea; + + SwingScrollPane(SwingTextArea textArea) + { + super(textArea, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, + JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); + + this.textArea = textArea; + } + + /** + * Returns this label. + * + * @return this + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to + * processMouseEvent(). + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + JViewport viewPort = getViewport(); + if(viewPort.contains(ev.getPoint())) + { + ev.setSource(textArea); + textArea.dispatchEvent(ev); + } + else + { + ev.setSource(this); + this.dispatchEvent(ev); + } + } + + /** + * Force lightweight mouse dispatching. + */ + public boolean isLightweight() + { + return false; + } + + /** + * Handles mouse motion events by forwarding it to + * processMouseMotionEvent(). + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + textArea.processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to processKeyEvent(). + * + * @param ev the mouse event + */ + public void handleKeyEvent(KeyEvent ev) + { + textArea.processKeyEvent(ev); + } + + /** + * Handles focus events by forwarding it to + * processFocusEvent(). + * + * @param ev the Focus event + */ + public void handleFocusEvent(FocusEvent ev) + { + textArea.processFocusEvent(ev); + } + + /** + * Overridden so that this method returns the correct value even without a + * peer. + * + * @return the screen location of the button + */ + public Point getLocationOnScreen() + { + return SwingTextAreaPeer.this.getLocationOnScreen(); + } + + /** + * Overridden so that the isShowing method returns the correct value for the + * swing button, even if it has no peer on its own. + * + * @return true if the button is currently showing, + * false otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (SwingTextAreaPeer.this.awtComponent != null) + retVal = SwingTextAreaPeer.this.awtComponent.isShowing(); + return retVal; + } + + /** + * Overridden, so that the Swing button can create an Image without its + * own peer. + * + * @param w the width of the image + * @param h the height of the image + * + * @return an image + */ + public Image createImage(int w, int h) + { + return SwingTextAreaPeer.this.createImage(w, h); + } + + public Graphics getGraphics() + { + return SwingTextAreaPeer.this.getGraphics(); + } + + public Container getParent() + { + Container par = null; + if (SwingTextAreaPeer.this.awtComponent != null) + par = SwingTextAreaPeer.this.awtComponent.getParent(); + return par; + } + + public void requestFocus() { + SwingTextAreaPeer.this.requestFocus(awtComponent, false, true, 0); + } + + public boolean requestFocus(boolean temporary) { + return SwingTextAreaPeer.this.requestFocus(awtComponent, temporary, + true, 0); + } + + } + + private class SwingTextArea extends JTextArea + { + /** + * Make this method accessible in this Package. + */ + protected final void processComponentKeyEvent(KeyEvent e) + { + super.processComponentKeyEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processMouseMotionEvent(MouseEvent ev) + { + super.processMouseMotionEvent(ev); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processComponentEvent(ComponentEvent e) + { + super.processComponentEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processFocusEvent(FocusEvent e) + { + super.processFocusEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processHierarchyBoundsEvent(HierarchyEvent e) + { + super.processHierarchyBoundsEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processHierarchyEvent(HierarchyEvent e) + { + super.processHierarchyEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processInputMethodEvent(InputMethodEvent e) + { + super.processInputMethodEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processMouseEvent(MouseEvent e) + { + super.processMouseEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processMouseWheelEvent(MouseWheelEvent e) + { + super.processMouseWheelEvent(e); + } + + /** + * Make this method accessible in this Package. + */ + protected final void processKeyEvent(KeyEvent e) + { + super.processKeyEvent(e); + } + + public void requestFocus() { + SwingTextAreaPeer.this.requestFocus(awtComponent, false, true, 0); + } + + public boolean requestFocus(boolean temporary) { + return SwingTextAreaPeer.this.requestFocus(awtComponent, temporary, + true, 0); + } + } + + /** + * The actual JTextArea. + */ + private SwingTextArea jTextArea; + + public SwingTextAreaPeer(TextArea textArea) + { + super(); + jTextArea = new SwingTextArea(); + SwingScrollPane swingArea = new SwingScrollPane(jTextArea); + init(textArea, swingArea); + + JViewport viewport = new JViewport() + { + public Image createImage(int width, int height) + { + return awtComponent.createImage(width, height); + } + }; + + viewport.setView(jTextArea); + swingArea.setViewport(viewport); + // Pull over the text from the text area. + setText(textArea.getText()); + + // Pull over the number of rows and columns + // if non were set use default values + int columns = textArea.getColumns(); + int rows = textArea.getRows(); + + if(columns == 0 && rows == 0) + { + columns = 25; + textArea.setColumns(columns); + rows = 5; + textArea.setRows(rows); + } + + jTextArea.setColumns(columns); + jTextArea.setRows(rows); + } + + public Dimension getMinimumSize(int rows, int cols) + { + return jTextArea.getMinimumSize(); + } + + public Dimension getPreferredSize(int rows, int cols) + { + return jTextArea.getPreferredSize(); + } + + public void insert(String text, int pos) + { + jTextArea.insert(text, pos); + } + + public void insertText(String text, int pos) + { + jTextArea.insert(text, pos); + } + + public Dimension minimumSize() + { + return jTextArea.getMinimumSize(); + } + + public Dimension preferredSize() + { + return jTextArea.getPreferredSize(); + } + + public Dimension minimumSize(int rows, int cols) + { + return jTextArea.getMinimumSize(); + } + + public Dimension preferredSize(int rows, int cols) + { + return jTextArea.getPreferredSize(); + } + + public void replaceRange(String text, int start, int end) + { + jTextArea.replaceRange(text, start, end); + } + + public void replaceText(String text, int start, int end) + { + jTextArea.replaceRange(text, start, end); + } + + public long filterEvents(long filter) + { + // TODO Auto-generated method stub + return 0; + } + + public int getCaretPosition() + { + return jTextArea.getCaretPosition(); + } + + public Rectangle getCharacterBounds(int pos) + { + Rectangle r; + try + { + return jTextArea.modelToView(pos); + } + catch (BadLocationException ex) + { + r = null; + } + return r; + } + + public int getIndexAtPoint(int x, int y) + { + return jTextArea.viewToModel(new Point(x, y)); + } + + public InputMethodRequests getInputMethodRequests() + { + // TODO Auto-generated method stub + return null; + } + + public int getSelectionEnd() + { + return jTextArea.getSelectionEnd(); + } + + public int getSelectionStart() + { + return jTextArea.getSelectionStart(); + } + + public String getText() + { + return jTextArea.getText(); + } + + public void select(int start, int end) + { + jTextArea.select(start, end); + } + + public void setCaretPosition(int pos) + { + jTextArea.setCaretPosition(pos); + } + + public void setEditable(boolean editable) + { + jTextArea.setEditable(editable); + } + + public void setText(String text) + { + jTextArea.setText(text); + } + + public void reshape(int x, int y, int width, int height) + { + if (swingComponent != null) + { + swingComponent.getJComponent().setBounds(x, y, width, height); + swingComponent.getJComponent().validate(); + } + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java new file mode 100644 index 000000000..9750c9bf7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingTextFieldPeer.java @@ -0,0 +1,411 @@ +/* SwingTextFieldPeer.java -- A Swing based peer for AWT textfields + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package gnu.java.awt.peer.swing; + +import java.awt.Container; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.TextField; +import java.awt.event.FocusEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.im.InputMethodRequests; +import java.awt.peer.TextFieldPeer; + +import javax.swing.JComponent; +import javax.swing.JTextField; + +/** + * A TextFieldPeer based on Swing JTextField. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class SwingTextFieldPeer + extends SwingComponentPeer + implements TextFieldPeer +{ + + /** + * A specialized Swing textfield for use in the peer. + * + * @author Roman Kennke (kennke@aicas.com) + */ + private class SwingTextField + extends JTextField + implements SwingComponent + { + + TextField textField; + + SwingTextField(TextField textField) + { + this.textField = textField; + } + + /** + * Overridden to provide normal behaviour even without a real peer + * attached. + * + * @return the location of the textfield on screen + */ + public Point getLocationOnScreen() + { + return SwingTextFieldPeer.this.getLocationOnScreen(); + } + + /** + * Overridden so that the isShowing method returns the correct value + * for the swing button, even if it has no peer on its own. + * + * @return true if the button is currently showing, + * false otherwise + */ + public boolean isShowing() + { + boolean retVal = false; + if (textField != null) + retVal = textField.isShowing(); + return retVal; + } + + /** + * Overridden, so that the Swing button can create an Image without its + * own peer. + * + * @param w the width of the image + * @param h the height of the image + * + * @return an image + */ + public Image createImage(int w, int h) + { + return SwingTextFieldPeer.this.createImage(w, h); + } + + /** + * Returns this textfield. + * + * @return this + */ + public JComponent getJComponent() + { + return this; + } + + /** + * Handles mouse events by forwarding it to the swing textfield. + * + * @param ev the mouse event + */ + public void handleMouseEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseEvent(ev); + } + + /** + * Handles mouse motion events by forwarding it to the swing textfield. + * + * @param ev the mouse motion event + */ + public void handleMouseMotionEvent(MouseEvent ev) + { + ev.setSource(this); + processMouseMotionEvent(ev); + } + + /** + * Handles key events by forwarding it to the swing textfield. + * + * @param ev the key event + */ + public void handleKeyEvent(KeyEvent ev) + { + ev.setSource(this); + processKeyEvent(ev); + } + + /** + * Handles focus events by forwarding it to + * processFocusEvent(). + * + * @param ev the Focus event + */ + public void handleFocusEvent(FocusEvent ev) + { + processFocusEvent(ev); + } + + + public Container getParent() + { + Container par = null; + if (textField != null) + par = textField.getParent(); + return par; + } + + public Graphics getGraphics() + { + return SwingTextFieldPeer.this.getGraphics(); + } + + public void requestFocus() { + SwingTextFieldPeer.this.requestFocus(awtComponent, false, true, 0); + } + + public boolean requestFocus(boolean temporary) { + return SwingTextFieldPeer.this.requestFocus(awtComponent, temporary, + true, 0); + } + + } + + /** + * Creates a new SwingTextFieldPeer instance for the specified + * AWT textfield. + * + * @param textField the AWT textfield + */ + public SwingTextFieldPeer(TextField textField) + { + SwingTextField swingTextField = new SwingTextField(textField); + swingTextField.setText(textField.getText()); + init(textField, swingTextField); + } + + /** + * Returns the minimum size of the textfield. + * + * @param len not used here + * + * @return the minimum size of the textfield + */ + public Dimension minimumSize(int len) + { + return swingComponent.getJComponent().getMinimumSize(); + } + + /** + * Returns the preferred size of the textfield. + * + * @param len not used here + * + * @return the preferred size of the textfield + */ + public Dimension preferredSize(int len) + { + return swingComponent.getJComponent().getPreferredSize(); + } + + /** + * Returns the minimum size of the textfield. + * + * @param len not used here + * + * @return the minimum size of the textfield + */ + public Dimension getMinimumSize(int len) + { + return swingComponent.getJComponent().getMinimumSize(); + } + + /** + * Returns the preferred size of the textfield. + * + * @param len not used here + * + * @return the preferred size of the textfield + */ + public Dimension getPreferredSize(int len) + { + return swingComponent.getJComponent().getPreferredSize(); + } + + /** + * Sets the echo character. + * + * @param echoChar the echo character to be set + */ + public void setEchoChar(char echoChar) + { + // TODO: Must be implemented. + } + + /** + * Sets the echo character. + * + * @param echoChar the echo character to be set + */ + public void setEchoCharacter(char echoChar) + { + // TODO: Must be implemented. + } + + /** + * Returns the end index of the current selection. + * + * @return the end index of the current selection + */ + public int getSelectionEnd() + { + // TODO: Must be implemented. + return 0; + } + + /** + * Returns the start index of the current selection. + * + * @return the start index of the current selection + */ + public int getSelectionStart() + { + // TODO: Must be implemented. + return 0; + } + + /** + * Returns the current content of the textfield. + * + * @return the current content of the textfield + */ + public String getText() + { + return ((JTextField) swingComponent.getJComponent()).getText(); + } + + /** + * Sets the content of the textfield. + * + * @param text the text to set + */ + public void setText(String text) + { + ((JTextField) swingComponent.getJComponent()).setText(text); + } + + /** + * Sets the current selection. + * + * @param startPos the start index of the selection + * @param endPos the start index of the selection + */ + public void select(int startPos, int endPos) + { + // TODO: Must be implemented. + } + + /** + * Sets the editable flag of the text field. + * + * @param editable true to make the textfield editable, + * false to make it uneditable + */ + public void setEditable(boolean editable) + { + ((JTextField) swingComponent.getJComponent()).setEditable(editable); + } + + /** + * Returns the current caret position. + * + * @return the current caret position + */ + public int getCaretPosition() + { + return ((JTextField) swingComponent.getJComponent()).getCaret().getDot(); + } + + /** + * Sets the current caret position. + * + * @param pos the caret position to set + */ + public void setCaretPosition(int pos) + { + ((JTextField) swingComponent.getJComponent()).getCaret().setDot(pos); + } + + /** + * Returns the index of the character at the specified location. + * + * @param x the X coordinate of the point to query + * @param y the Y coordinate of the point to query + * + * @return the index of the character at the specified location + */ + public int getIndexAtPoint(int x, int y) + { + // TODO: Must be implemented. + return 0; + } + + /** + * Returns the bounds of the character at the specified index. + * + * @param pos the index of the character + * + * @return the bounds of the character at the specified index + */ + public Rectangle getCharacterBounds(int pos) + { + // TODO: Must be implemented. + return null; + } + + /** + * Not used. + */ + public long filterEvents(long filter) + { + // TODO: Must be implemented. + return 0; + } + + /** + * Not used. + */ + public InputMethodRequests getInputMethodRequests() + { + // TODO: Must be implemented. + return null; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingToolkit.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingToolkit.java new file mode 100644 index 000000000..63414050b --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingToolkit.java @@ -0,0 +1,181 @@ +/* SwingToolkit.java -- A base toolkit for Swing peers + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.swing; + +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Dialog; +import java.awt.Label; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.TextField; +import java.awt.peer.ButtonPeer; +import java.awt.peer.CanvasPeer; +import java.awt.peer.LabelPeer; +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.TextFieldPeer; + +import gnu.java.awt.ClasspathToolkit; + +/** + * A base implementation for {@link java.awt.Toolkit} that provides the + * Swing based widgets. Concrete implementations still must provide the + * remaining abstract methods. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public abstract class SwingToolkit extends ClasspathToolkit +{ + + /** + * Creates a SwingButtonPeer. + * + * @param button the AWT button + * + * @return the Swing button peer + */ + protected ButtonPeer createButton(Button button) + { + return new SwingButtonPeer(button); + } + + /** + * Creates a SwingCanvasPeer. + * + * @param canvas the AWT canvas + * + * @return the Swing canvas peer + */ + protected CanvasPeer createCanvas(Canvas canvas) + { + return new SwingCanvasPeer(canvas); + } + + /** + * Creates a SwingLabelPeer. + * + * @param label the AWT label + * + * @return the Swing label peer + */ + protected LabelPeer createLabel(Label label) + { + return new SwingLabelPeer(label); + } + + /** + * Creates a SwingMenuPeer. + * + * @param menu the AWT menu + * + * @return the Swing menu peer + */ + protected MenuPeer createMenu(Menu menu) + { + return new SwingMenuPeer(menu); + } + + /** + * Creates a SwingMenuBarPeer. + * + * @param menuBar the AWT menubar + * + * @return the Swing menu bar peer + */ + protected MenuBarPeer createMenuBar(MenuBar menuBar) + { + return new SwingMenuBarPeer(menuBar); + } + + /** + * Creates a SwingMenuItemPeer. + * + * @param menuItem the AWT menu item + * + * @return the Swing menu item peer + */ + protected MenuItemPeer createMenuItem(MenuItem menuItem) + { + return new SwingMenuItemPeer(menuItem); + } + + /** + * Creates a SwingPanelPeer. + * + * @param panel the AWT panel + * + * @return the Swing panel peer + */ + protected PanelPeer createPanel(Panel panel) + { + return new SwingPanelPeer(panel); + } + + /** + * Creates a SwingTextFieldPeer. + * + * @param textField the AWT text field + * + * @return the Swing text field peer + */ + protected TextFieldPeer createTextField(TextField textField) + { + return new SwingTextFieldPeer(textField); + } + + @Override + public boolean isModalExclusionTypeSupported + (Dialog.ModalExclusionType modalExclusionType) + { + return false; + } + + @Override + public boolean isModalityTypeSupported(Dialog.ModalityType modalityType) + { + return false; + } + + +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java new file mode 100644 index 000000000..bdc494e95 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/SwingWindowPeer.java @@ -0,0 +1,99 @@ +/* SwingWindowPeer.java -- An abstract base for Swing based window peers + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.swing; + +import java.awt.Window; +import java.awt.peer.ComponentPeer; +import java.awt.peer.WindowPeer; + +/** + * An abstract base class for Swing based WindowPeer implementation. Concrete + * implementations of WindowPeers should subclass this class in order to get + * the correct behaviour. + * + * As a minimum, a subclass must implement all the remaining abstract methods + * as well as the following methods: + *
    + *
  • {@link ComponentPeer#getLocationOnScreen()}
  • + *
  • {@link ComponentPeer#getGraphics()}
  • + *
  • {@link ComponentPeer#createImage(int, int)}
  • + *
+ * + * @author Roman Kennke (kennke@aicas.com) + */ +public abstract class SwingWindowPeer + extends SwingContainerPeer + implements WindowPeer +{ + + /** + * Creates a new instance of WindowPeer. + * + * @param window the AWT window + */ + public SwingWindowPeer(Window window) + { + super(window); + init(window, null); + } + + public void updateIconImages() + { + // TODO: Implement properly. + } + + public void updateMinimumSize() + { + // TODO: Implement properly. + } + + public void setModalBlocked(java.awt.Dialog d, boolean b) + { + // TODO: Implement properly. + } + + public void updateFocusableWindowState() + { + // TODO: Implement properly. + } + + public void setAlwaysOnTop(boolean b) + { + // TODO: Implement properly. + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/swing/package.html b/libjava/classpath/gnu/java/awt/peer/swing/package.html new file mode 100644 index 000000000..506eda883 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/swing/package.html @@ -0,0 +1,71 @@ + + + + + + Swing based AWT peers + + +

Swing based AWT peers.

+

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

+

An actual implementation would have to provide the following: +

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

+ + diff --git a/libjava/classpath/gnu/java/awt/peer/x/GLGraphics.java b/libjava/classpath/gnu/java/awt/peer/x/GLGraphics.java new file mode 100644 index 000000000..3cf3797ab --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/GLGraphics.java @@ -0,0 +1,134 @@ +/* GLGraphics.java -- Graphics2D impl on top of GLX + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.x; + +import java.awt.Color; +import java.awt.GraphicsConfiguration; +import java.awt.Rectangle; +import java.awt.image.ColorModel; +import java.util.Map; + +import gnu.java.awt.java2d.AbstractGraphics2D; +import gnu.x11.extension.glx.GL; + +/** + * An implementation of Graphics2D on top of the GLX extension of X. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class GLGraphics extends AbstractGraphics2D +{ + + /** + * The rendering context. + */ + private GL gl; + + /** + * Creates a new GLGraphics that paints on the specified GL context. + * + * @param g the GL context to paint to + */ + GLGraphics(GL g) + { + gl = g; + } + + public void setBackground(Color b) + { + super.setBackground(b); + + gl.clearColor(b.getRed() / 255.F, b.getGreen() / 255.F, + b.getBlue() / 255.F, b.getAlpha() / 255.F); + } + + public void clearRect(int x, int y, int w, int h) + { + // TODO: Maybe use fillRect(). + gl.clear(GL.COLOR_BUFFER_BIT); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + gl.begin(GL.LINES); + gl.vertex2i(x1, y1); + gl.vertex2i(x2, y2); + gl.end(); + // TODO: Maybe do: + // gl.flush(); + } + + public void drawRect(int x, int y, int w, int h) + { + gl.polygon_mode(GL.FRONT_AND_BACK, GL.LINE); + gl.begin(GL.POLYGON); + gl.recti(x, y, x + w, y + h); + gl.end(); + // TODO: Maybe do: + // gl.flush(); + } + + public void fillRect(int x, int y, int w, int h) + { + gl.polygon_mode(GL.FRONT_AND_BACK, GL.FILL); + gl.recti(x, y, x + w, y + h); + // TODO: Maybe do: + // gl.flush(); + } + + protected ColorModel getColorModel() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + @Override + protected Rectangle getDeviceBounds() + { + // FIXME: not sure it's correct + return new Rectangle(0, 0, + gl.display.default_screen.width, + gl.display.default_screen.height); + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/KeyboardMapping.java b/libjava/classpath/gnu/java/awt/peer/x/KeyboardMapping.java new file mode 100644 index 000000000..c982a30d5 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/KeyboardMapping.java @@ -0,0 +1,419 @@ +/* KeyboardMapping.java -- Maps X keysyms to Java keyCode and keyChar + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.x; + +import gnu.x11.Input; +import gnu.x11.keysym.Latin1; +import gnu.x11.keysym.Misc; + +import java.awt.event.KeyEvent; + +/** + * Defines the keyboard mapping from X keysyms to Java + * keycodes and keychars. + * + * @author Roman Kennke (kennke@aicas.com) + */ +final class KeyboardMapping +{ + + /** + * Maps X keycodes to AWT keycodes. + * + * @param xInput the X input event + * @param xKeyCode the X keycode to map + * @param xMods the X modifiers + * + * @return the AWT keycode and keychar + */ + static int mapToKeyCode(gnu.x11.Input xInput, int xKeyCode, int xMods) + { + int mapped = KeyEvent.VK_UNDEFINED; + int keysym = xInput.keycode_to_keysym(xKeyCode, xMods, true); + + // Special keys. + if (keysym >= 255 << 8) + { + // FIXME: Add missing mappings. + switch (keysym) + { + case Misc.BACKSPACE: + mapped = KeyEvent.VK_BACK_SPACE; + break; + case Misc.TAB: + mapped = KeyEvent.VK_TAB; + break; + case Misc.CLEAR: + mapped = KeyEvent.VK_CLEAR; + break; + case Misc.RETURN: + mapped = KeyEvent.VK_ENTER; + break; + case Misc.PAUSE: + mapped = KeyEvent.VK_PAUSE; + break; + case Misc.SCROLL_LOCK: + mapped = KeyEvent.VK_SCROLL_LOCK; + break; + case Misc.ESCAPE: + mapped = KeyEvent.VK_ESCAPE; + break; + case Misc.HOME: + mapped = KeyEvent.VK_HOME; + break; + case Misc.LEFT: + mapped = KeyEvent.VK_LEFT; + break; + case Misc.UP: + mapped = KeyEvent.VK_UP; + break; + case Misc.RIGHT: + mapped = KeyEvent.VK_RIGHT; + break; + case Misc.DOWN: + mapped = KeyEvent.VK_DOWN; + break; + case Misc.PAGE_UP: + mapped = KeyEvent.VK_PAGE_UP; + break; + case Misc.PAGE_DOWN: + mapped = KeyEvent.VK_PAGE_DOWN; + break; + case Misc.END: + mapped = KeyEvent.VK_END; + break; + case Misc.BEGIN: + mapped = KeyEvent.VK_BEGIN; + break; + case Misc.INSERT: + mapped = KeyEvent.VK_INSERT; + break; + case Misc.UNDO: + mapped = KeyEvent.VK_UNDO; + break; + case Misc.FIND: + mapped = KeyEvent.VK_FIND; + break; + case Misc.CANCEL: + mapped = KeyEvent.VK_CANCEL; + break; + case Misc.HELP: + mapped = KeyEvent.VK_HELP; + break; + case Misc.MODE_SWITCH: + mapped = KeyEvent.VK_MODECHANGE; + break; + case Misc.NUM_LOCK: + mapped = KeyEvent.VK_NUM_LOCK; + break; + case Misc.KP_LEFT: + mapped = KeyEvent.VK_KP_LEFT; + break; + case Misc.KP_UP: + mapped = KeyEvent.VK_KP_UP; + break; + case Misc.KP_RIGHT: + mapped = KeyEvent.VK_KP_RIGHT; + break; + case Misc.KP_DOWN: + mapped = KeyEvent.VK_KP_DOWN; + break; + case Misc.F1: + mapped = KeyEvent.VK_F1; + break; + case Misc.F2: + mapped = KeyEvent.VK_F2; + break; + case Misc.F3: + mapped = KeyEvent.VK_F3; + break; + case Misc.F4: + mapped = KeyEvent.VK_F4; + break; + case Misc.F5: + mapped = KeyEvent.VK_F5; + break; + case Misc.F6: + mapped = KeyEvent.VK_F6; + break; + case Misc.F7: + mapped = KeyEvent.VK_F7; + break; + case Misc.F8: + mapped = KeyEvent.VK_F8; + break; + case Misc.F9: + mapped = KeyEvent.VK_F9; + break; + case Misc.F10: + mapped = KeyEvent.VK_F10; + break; + case Misc.F11: + mapped = KeyEvent.VK_F11; + break; + case Misc.F12: + mapped = KeyEvent.VK_F12; + break; + case Misc.F13: + mapped = KeyEvent.VK_F13; + break; + case Misc.F14: + mapped = KeyEvent.VK_F14; + break; + case Misc.F15: + mapped = KeyEvent.VK_F15; + break; + case Misc.F16: + mapped = KeyEvent.VK_F16; + break; + case Misc.F17: + mapped = KeyEvent.VK_F17; + break; + case Misc.F18: + mapped = KeyEvent.VK_F18; + break; + case Misc.F19: + mapped = KeyEvent.VK_F19; + break; + case Misc.F20: + mapped = KeyEvent.VK_F20; + break; + case Misc.F21: + mapped = KeyEvent.VK_F21; + break; + case Misc.F22: + mapped = KeyEvent.VK_F22; + break; + case Misc.F23: + mapped = KeyEvent.VK_F23; + break; + case Misc.F24: + mapped = KeyEvent.VK_F24; + break; + case Misc.SHIFT_L: + case Misc.SHIFT_R: + mapped = KeyEvent.VK_SHIFT; + break; + case Misc.CONTROL_L: + case Misc.CONTROL_R: + mapped = KeyEvent.VK_CONTROL; + break; + case Misc.CAPS_LOCK: + case Misc.SHIFT_LOCK: + mapped = KeyEvent.VK_CAPS_LOCK; + break; + case Misc.META_L: + case Misc.META_R: + mapped = KeyEvent.VK_META; + break; + case Misc.ALT_L: + case Misc.ALT_R: + mapped = KeyEvent.VK_ALT; + break; + case Misc.DELETE: + mapped = KeyEvent.VK_DELETE; + break; + default: + mapped = KeyEvent.VK_UNDEFINED; + } + } + // Map Latin1 characters. + else if (keysym < 256) + { + // TODO: Add missing mappings, if any. + // Lowercase characters are mapped to + // their corresponding upper case pendants. + if (keysym >= Latin1.A_SMALL && keysym <= Latin1.Z_SMALL) + mapped = keysym - 0x20; + // Uppercase characters are mapped 1:1. + else if (keysym >= Latin1.A && keysym <= Latin1.Z) + mapped = keysym; + // Digits are mapped 1:1. + else if (keysym >= Latin1.NUM_0 && keysym <= Latin1.NUM_9) + mapped = keysym; + else + { + switch (keysym) + { + case Latin1.SPACE: + mapped = KeyEvent.VK_SPACE; + break; + case Latin1.EXCLAM: + mapped = KeyEvent.VK_EXCLAMATION_MARK; + break; + case Latin1.QUOTE_DBL: + mapped = KeyEvent.VK_QUOTEDBL; + break; + case Latin1.NUMBER_SIGN: + mapped = KeyEvent.VK_NUMBER_SIGN; + break; + case Latin1.DOLLAR: + mapped = KeyEvent.VK_DOLLAR; + break; + case Latin1.AMPERSAND: + mapped = KeyEvent.VK_AMPERSAND; + break; + case Latin1.APOSTROPHE: + mapped = KeyEvent.VK_QUOTE; + break; + case Latin1.PAREN_LEFT: + mapped = KeyEvent.VK_LEFT_PARENTHESIS; + break; + case Latin1.PAREN_RIGHT: + mapped = KeyEvent.VK_RIGHT_PARENTHESIS; + break; + case Latin1.ASTERISK: + mapped = KeyEvent.VK_ASTERISK; + break; + case Latin1.PLUS: + mapped = KeyEvent.VK_PLUS; + break; + case Latin1.COMMA: + mapped = KeyEvent.VK_COMMA; + break; + case Latin1.MINUS: + mapped = KeyEvent.VK_MINUS; + break; + case Latin1.PERIOD: + mapped = KeyEvent.VK_PERIOD; + break; + case Latin1.SLASH: + mapped = KeyEvent.VK_SLASH; + break; + case Latin1.COLON: + mapped = KeyEvent.VK_COLON; + break; + case Latin1.SEMICOLON: + mapped = KeyEvent.VK_SEMICOLON; + break; + case Latin1.LESS: + mapped = KeyEvent.VK_LESS; + break; + case Latin1.EQUAL: + mapped = KeyEvent.VK_EQUALS; + break; + case Latin1.GREATER: + mapped = KeyEvent.VK_GREATER; + break; + case Latin1.AT: + mapped = KeyEvent.VK_AT; + break; + case Latin1.BRACKET_LEFT: + mapped = KeyEvent.VK_OPEN_BRACKET; + break; + case Latin1.BACKSLASH: + mapped = KeyEvent.VK_BACK_SLASH; + break; + case Latin1.BRACKET_RIGHT: + mapped = KeyEvent.VK_CLOSE_BRACKET; + break; + case Latin1.ASCII_CIRCUM: + mapped = KeyEvent.VK_CIRCUMFLEX; + break; + case Latin1.UNDERSCORE: + mapped = KeyEvent.VK_UNDERSCORE; + break; + case Latin1.GRAVE: + mapped = KeyEvent.VK_DEAD_GRAVE; + break; + case Latin1.BRACE_LEFT: + mapped = KeyEvent.VK_BRACELEFT; + break; + case Latin1.BRACE_RIGHT: + mapped = KeyEvent.VK_BRACERIGHT; + break; + case Latin1.ASCII_TILDE: + mapped = KeyEvent.VK_DEAD_TILDE; + break; + case Latin1.EXCLAM_DOWN: + mapped = KeyEvent.VK_INVERTED_EXCLAMATION_MARK; + break; + default: + mapped = KeyEvent.VK_UNDEFINED; + } + } + } + return mapped; + } + + /** + * Maps X keycodes+modifiers to Java keychars. + * + * @param xInput The X Input to use for mapping + * @param xKeyCode the X keycode + * @param xMods the X key modifiers + * + * @return the Java keychar + */ + static char mapToKeyChar(gnu.x11.Input xInput, int xKeyCode, int xMods) + { + char mapped = KeyEvent.CHAR_UNDEFINED; + char keysym = (char) xInput.keycode_to_keysym(xKeyCode, xMods, false); + // FIXME: Map other encodings properly. + if (keysym < 256) // Latin1. + { + mapped = keysym; + } + return mapped; + } + + /** + * Maps X modifier masks to AWT modifier masks. + * + * @param xMods the X modifiers + * + * @return the AWT modifiers + */ + static int mapModifiers(int xMods) + { + int mods = 0; + + if ((xMods & Input.SHIFT_MASK) != 0) + mods |= KeyEvent.SHIFT_MASK | KeyEvent.SHIFT_DOWN_MASK; + if ((xMods & Input.META_MASK) != 0) + mods |= KeyEvent.META_MASK | KeyEvent.META_DOWN_MASK; + if ((xMods & Input.ALT_MASK) != 0) + mods |= KeyEvent.ALT_MASK | KeyEvent.ALT_DOWN_MASK; + if ((xMods & Input.MOD5_MASK) != 0) + mods |= KeyEvent.ALT_GRAPH_MASK | KeyEvent.ALT_GRAPH_DOWN_MASK; + if ((xMods & Input.CONTROL_MASK) != 0) + mods |= KeyEvent.CTRL_MASK | KeyEvent.CTRL_DOWN_MASK; + + return mods; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/PixmapVolatileImage.java b/libjava/classpath/gnu/java/awt/peer/x/PixmapVolatileImage.java new file mode 100644 index 000000000..131647fab --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/PixmapVolatileImage.java @@ -0,0 +1,185 @@ +/* PixmapVolatileImage.java -- VolatileImage implementation around a Pixmap + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.x; + +import gnu.x11.GC; +import gnu.x11.Pixmap; +import gnu.x11.image.Image; +import gnu.x11.image.ZPixmap; + +import java.awt.Graphics2D; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsEnvironment; +import java.awt.ImageCapabilities; +import java.awt.Point; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.ComponentSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.ImageObserver; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; + +/** + * A {@link VolatileImage} implementation that wraps an X Pixmap. + */ +class PixmapVolatileImage + extends VolatileImage +{ + + /** + * The shared capabilities instance. + */ + private static final ImageCapabilities caps = new ImageCapabilities(true); + + /** + * The underlying pixmap. + */ + private Pixmap pixmap; + + /** + * Creates a new PixmapVolatileImage. + * + * @param w the width of the image + * @param h the height of the image + */ + public PixmapVolatileImage(int w, int h) + { + GraphicsEnvironment env = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + XGraphicsDevice dev = (XGraphicsDevice) env.getDefaultScreenDevice(); + pixmap = new Pixmap(dev.getDisplay(), w, h); + + // Clear pixmap. + GC gc = new GC(pixmap); + gc.set_foreground(0xffffffff); + pixmap.fill_rectangle(gc, 0, 0, w, h); + + } + + @Override + public boolean contentsLost() + { + return false; + } + + @Override + public Graphics2D createGraphics() + { + return new XGraphics2D(pixmap); + } + + @Override + public ImageCapabilities getCapabilities() + { + return caps; + } + + @Override + public int getHeight() + { + return pixmap.height; + } + + @Override + public BufferedImage getSnapshot() + { + // TODO: Support non-24-bit resolutions. + int w = pixmap.width; + int h = pixmap.height; + ZPixmap zpixmap = (ZPixmap) pixmap.image(0, 0, w, h, 0xffffffff, + Image.Format.ZPIXMAP); + DataBuffer buffer = new ZPixmapDataBuffer(zpixmap); + SampleModel sm = new ComponentSampleModel(DataBuffer.TYPE_BYTE, w, h, 4, + w * 4, + new int[]{0, 1, 2, 3 }); + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB); + ColorModel cm = new ComponentColorModel(cs, true, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + WritableRaster raster = Raster.createWritableRaster(sm, buffer, + new Point(0, 0)); + return new BufferedImage(cm, raster, false, null); + } + + @Override + public int getWidth() + { + return pixmap.width; + } + + @Override + public int validate(GraphicsConfiguration gc) + { + // TODO: Check compatibility with gc. + return IMAGE_OK; + } + + @Override + public int getHeight(ImageObserver observer) + { + return getHeight(); + } + + @Override + public Object getProperty(String name, ImageObserver observer) + { + return null; + } + + @Override + public int getWidth(ImageObserver observer) + { + return getWidth(); + } + + /** + * Returns the underlying X pixmap. This is used for the graphics code. + * + * @return the underlying X pixmap + */ + Pixmap getPixmap() + { + return pixmap; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XDialogPeer.java b/libjava/classpath/gnu/java/awt/peer/x/XDialogPeer.java new file mode 100644 index 000000000..45ad24d67 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XDialogPeer.java @@ -0,0 +1,61 @@ +/* XDialogPeer.java -- The peer for AWT dialogs + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.x; + +import java.awt.Dialog; +import java.awt.peer.DialogPeer; + +public class XDialogPeer + extends XWindowPeer + implements DialogPeer +{ + + XDialogPeer(Dialog target) + { + super(target); + } + + public void setResizable(boolean resizeable) + { + } + + public void setTitle(String title) + { + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XEventPump.java b/libjava/classpath/gnu/java/awt/peer/x/XEventPump.java new file mode 100644 index 000000000..8e80b97a3 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XEventPump.java @@ -0,0 +1,486 @@ +/* XEventPump.java -- Pumps events from X to AWT + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.x; + +import java.awt.AWTEvent; +import java.awt.Component; +import java.awt.Container; +import java.awt.Graphics; +import java.awt.Insets; +import java.awt.Rectangle; +import java.awt.Toolkit; +import java.awt.Window; +import java.awt.event.ComponentEvent; +import java.awt.event.KeyEvent; +import java.awt.event.MouseEvent; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; +import java.util.HashMap; + +import gnu.java.awt.ComponentReshapeEvent; +import gnu.x11.Atom; +import gnu.x11.Display; +import gnu.x11.event.ButtonPress; +import gnu.x11.event.ButtonRelease; +import gnu.x11.event.ClientMessage; +import gnu.x11.event.ConfigureNotify; +import gnu.x11.event.DestroyNotify; +import gnu.x11.event.Event; +import gnu.x11.event.Expose; +import gnu.x11.event.Input; +import gnu.x11.event.KeyPress; +import gnu.x11.event.KeyRelease; +import gnu.x11.event.MotionNotify; +import gnu.x11.event.PropertyNotify; +import gnu.x11.event.ResizeRequest; +import gnu.x11.event.UnmapNotify; + +/** + * Fetches events from X, translates them to AWT events and pumps them up + * into the AWT event queue. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class XEventPump + implements Runnable +{ + + /** + * The X Display from which we fetch and pump up events. + */ + private Display display; + + /** + * Maps X Windows to AWT Windows to be able to correctly determine the + * event targets. + */ + private HashMap windows; + + /** + * Indicates if we are currently inside a drag operation. This is + * set to the button ID when a button is pressed and to -1 (indicating + * that no drag is active) when the mouse is released. + */ + private int drag; + + /** + * Creates a new XEventPump for the specified X Display. + * + * @param d the X Display + */ + XEventPump(Display d) + { + display = d; + windows = new HashMap(); + drag = -1; + Thread thread = new Thread(this, "X Event Pump"); + thread.setDaemon(true); + thread.start(); + } + + /** + * The main event pump loop. This basically fetches events from the + * X Display and pumps them into the system event queue. + */ + public void run() + { + while (display.connected) + { + try + { + Event xEvent = display.next_event(); + handleEvent(xEvent); + } + catch (ThreadDeath death) + { + // If someone wants to kill us, let them. + return; + } + catch (Throwable x) + { + System.err.println("Exception during event dispatch:"); + x.printStackTrace(System.err); + } + } + } + + /** + * Adds an X Window to AWT Window mapping. This is required so that the + * event pump can correctly determine the event targets. + * + * @param xWindow the X Window + * @param awtWindow the AWT Window + */ + void registerWindow(gnu.x11.Window xWindow, Window awtWindow) + { + if (XToolkit.DEBUG) + System.err.println("registering window id: " + xWindow.id); + windows.put(new Integer(xWindow.id), awtWindow); + } + + void unregisterWindow(gnu.x11.Window xWindow) + { + windows.remove(new Integer(xWindow.id)); + } + + private void handleButtonPress(ButtonPress event) + { + Integer key = new Integer(event.getEventWindowID()); + Window awtWindow = (Window) windows.get(key); + + // Create and post the mouse event. + int button = event.detail(); + + // AWT cannot handle more than 3 buttons and expects 0 instead. + if (button >= gnu.x11.Input.BUTTON3) + button = 0; + drag = button; + + Component target = + findMouseEventTarget(awtWindow, event.getEventX(), event.getEventY()); + if(target == null) + { + target = awtWindow; + } + + MouseEvent mp = new MouseEvent(target, MouseEvent.MOUSE_PRESSED, + System.currentTimeMillis(), + KeyboardMapping.mapModifiers(event.getState()) + | buttonToModifier(button), + event.getEventX(), event.getEventY(), + 1, false, button); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mp); + } + + private void handleButtonRelease(ButtonRelease event) + { + Integer key = new Integer(event.getEventWindowID()); + Window awtWindow = (Window) windows.get(key); + + int button = event.detail(); + + // AWT cannot handle more than 3 buttons and expects 0 instead. + if (button >= gnu.x11.Input.BUTTON3) + button = 0; + drag = -1; + + Component target = + findMouseEventTarget(awtWindow, event.getEventX(), event.getEventY()); + if(target == null) + { + target = awtWindow; + } + + MouseEvent mr = new MouseEvent(target, MouseEvent.MOUSE_RELEASED, + System.currentTimeMillis(), + KeyboardMapping.mapModifiers(event.getState()) + | buttonToModifier(button), + event.getEventX(), event.getEventY(), + 1, false, button); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mr); + } + + + private void handleMotionNotify(MotionNotify event) + { + Integer key = new Integer(event.getEventWindowID()); + Window awtWindow = (Window) windows.get(key); + + int button = event.detail(); + + // AWT cannot handle more than 3 buttons and expects 0 instead. + if (button >= gnu.x11.Input.BUTTON3) + button = 0; + + MouseEvent mm = null; + if (drag == -1) + { + mm = new MouseEvent(awtWindow, MouseEvent.MOUSE_MOVED, + System.currentTimeMillis(), + KeyboardMapping.mapModifiers(event.getState()) + | buttonToModifier(button), + event.getEventX(), event.getEventY(), + 1, false); + + } + else + { + mm = new MouseEvent(awtWindow, MouseEvent.MOUSE_DRAGGED, + System.currentTimeMillis(), + KeyboardMapping.mapModifiers(event.getState()) + | buttonToModifier(drag), + event.getEventX(), event.getEventY(), + 1, false); + } + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(mm); + } + + // FIME: refactor and make faster, maybe caching the event and handle + // and/or check timing (timing is generated for PropertyChange)? + private void handleExpose(Expose event) + { + Integer key = new Integer(event.window_id); + Window awtWindow = (Window) windows.get(key); + + if (XToolkit.DEBUG) + System.err.println("expose request for window id: " + key); + + Rectangle r = new Rectangle(event.x(), event.y(), event.width(), + event.height()); + // We need to clear the background of the exposed rectangle. + assert awtWindow != null : "awtWindow == null for window ID: " + key; + + Graphics g = awtWindow.getGraphics(); + g.clearRect(r.x, r.y, r.width, r.height); + g.dispose(); + + XWindowPeer xwindow = (XWindowPeer) awtWindow.getPeer(); + Insets i = xwindow.insets(); + if (event.width() != awtWindow.getWidth() - i.left - i.right + || event.height() != awtWindow.getHeight() - i.top - i.bottom) + { + int w = event.width(); + int h = event.height(); + int x = xwindow.xwindow.x; + int y = xwindow.xwindow.y; + + if (XToolkit.DEBUG) + System.err.println("Setting size on AWT window: " + w + + ", " + h + ", " + awtWindow.getWidth() + + ", " + awtWindow.getHeight()); + + // new width and height + xwindow.xwindow.width = w; + xwindow.xwindow.height = h; + + // reshape the window + ComponentReshapeEvent cre = + new ComponentReshapeEvent(awtWindow, x, y, w, h); + awtWindow.dispatchEvent(cre); + } + + ComponentEvent ce = + new ComponentEvent(awtWindow, ComponentEvent.COMPONENT_RESIZED); + awtWindow.dispatchEvent(ce); + + PaintEvent pev = new PaintEvent(awtWindow, PaintEvent.UPDATE, r); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(pev); + } + + private void handleDestroyNotify(DestroyNotify destroyNotify) + { + if (XToolkit.DEBUG) + System.err.println("DestroyNotify event: " + destroyNotify); + + Integer key = new Integer(destroyNotify.event_window_id); + Window awtWindow = (Window) windows.get(key); + + AWTEvent event = new WindowEvent(awtWindow, WindowEvent.WINDOW_CLOSED); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(event); + } + + private void handleClientMessage(ClientMessage clientMessage) + { + if (XToolkit.DEBUG) + System.err.println("ClientMessage event: " + clientMessage); + + if (clientMessage.delete_window()) + { + if (XToolkit.DEBUG) + System.err.println("ClientMessage is a delete_window event"); + + Integer key = new Integer(clientMessage.window_id); + Window awtWindow = (Window) windows.get(key); + + AWTEvent event = new WindowEvent(awtWindow, WindowEvent.WINDOW_CLOSING); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(event); + } + } + + private void handleEvent(Event xEvent) + { + if (XToolkit.DEBUG) + System.err.println("fetched event: " + xEvent); + + switch (xEvent.code() & 0x7f) + { + case ButtonPress.CODE: + this.handleButtonPress((ButtonPress) xEvent); + break; + case ButtonRelease.CODE: + this.handleButtonRelease((ButtonRelease) xEvent); + break; + case MotionNotify.CODE: + this.handleMotionNotify((MotionNotify) xEvent); + break; + case Expose.CODE: + this.handleExpose((Expose) xEvent); + break; + case KeyPress.CODE: + case KeyRelease.CODE: + Integer key = new Integer(((Input) xEvent).getEventWindowID()); + Window awtWindow = (Window) windows.get(key); + handleKeyEvent(xEvent, awtWindow); + break; + case DestroyNotify.CODE: + this.handleDestroyNotify((DestroyNotify) xEvent); + break; + case ClientMessage.CODE: + this.handleClientMessage((ClientMessage) xEvent); + break; + case PropertyNotify.CODE: + key = new Integer (((PropertyNotify) xEvent).getWindowID()); + awtWindow = (Window) windows.get(key); + AWTEvent event = new WindowEvent(awtWindow, WindowEvent.WINDOW_STATE_CHANGED); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(event); + break; + default: + if (XToolkit.DEBUG) + System.err.println("Unhandled X event: " + xEvent); + } + } + + /** + * Handles key events from X. + * + * @param xEvent the X event + * @param awtWindow the AWT window to which the event gets posted + */ + private void handleKeyEvent(Event xEvent, Window awtWindow) + { + Input keyEvent = (Input) xEvent; + int xKeyCode = keyEvent.detail(); + int xMods = keyEvent.getState(); + int keyCode = KeyboardMapping.mapToKeyCode(xEvent.display.input, xKeyCode, + xMods); + char keyChar = KeyboardMapping.mapToKeyChar(xEvent.display.input, xKeyCode, + xMods); + if (XToolkit.DEBUG) + System.err.println("XEventPump.handleKeyEvent: " + xKeyCode + ", " + + xMods + ": " + ((int) keyChar) + ", " + keyCode); + int awtMods = KeyboardMapping.mapModifiers(xMods); + long when = System.currentTimeMillis(); + KeyEvent ke; + if (keyEvent.code() == KeyPress.CODE) + { + ke = new KeyEvent(awtWindow, KeyEvent.KEY_PRESSED, when, + awtMods, keyCode, + KeyEvent.CHAR_UNDEFINED); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke); + if (keyChar != KeyEvent.CHAR_UNDEFINED) + { + ke = new KeyEvent(awtWindow, KeyEvent.KEY_TYPED, when, + awtMods, KeyEvent.VK_UNDEFINED, + keyChar); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke); + } + + } + else + { + ke = new KeyEvent(awtWindow, KeyEvent.KEY_RELEASED, when, + awtMods, keyCode, + KeyEvent.CHAR_UNDEFINED); + Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ke); + } + + } + + /** Translates an X button identifier to the AWT's MouseEvent modifier + * mask. As the AWT cannot handle more than 3 buttons those return + * 0. + */ + static int buttonToModifier(int button) + { + switch (button) + { + case gnu.x11.Input.BUTTON1: + return MouseEvent.BUTTON1_DOWN_MASK | MouseEvent.BUTTON1_MASK; + case gnu.x11.Input.BUTTON2: + return MouseEvent.BUTTON2_DOWN_MASK | MouseEvent.BUTTON2_MASK; + case gnu.x11.Input.BUTTON3: + return MouseEvent.BUTTON3_DOWN_MASK | MouseEvent.BUTTON3_MASK; + } + + return 0; + } + + /** + * Finds the heavyweight mouse event target. + * + * @param src the original source of the event + * + * @param pt the event coordinates + * + * @return the real mouse event target + */ + private Component findMouseEventTarget(Component src, int x, int y) + { + Component found = null; + if (src instanceof Container) + { + Container cont = (Container) src; + int numChildren = cont.getComponentCount(); + for (int i = 0; i < numChildren && found == null; i++) + { + Component child = cont.getComponent(i); + if (child != null && child.isVisible() + && child.contains(x - child.getX(), y - child.getY())) + { + if (child instanceof Container) + { + Component deeper = findMouseEventTarget(child, + x - child.getX(), + y - child.getY()); + if (deeper != null) + found = deeper; + } + else if (! child.isLightweight()) + found = child; + } + } + } + + // Consider the source itself. + if (found == null && src.contains(x, y) && ! src.isLightweight()) + found = src; + + return found; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XFontPeer.java b/libjava/classpath/gnu/java/awt/peer/x/XFontPeer.java new file mode 100644 index 000000000..190209014 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XFontPeer.java @@ -0,0 +1,770 @@ +/* XFontPeer.java -- The font peer for X + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.x; + +import gnu.java.lang.CPStringBuilder; + +import java.awt.AWTError; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.LineMetrics; +import java.awt.font.TextAttribute; +import java.awt.geom.Rectangle2D; +import java.io.IOException; +import java.io.InputStream; +import java.text.CharacterIterator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Locale; +import java.util.Map; +import java.util.Properties; + +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.x11.Display; +import gnu.x11.Fontable; + +/** + * The bridge from AWT to X fonts. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class XFontPeer + extends ClasspathFontPeer +{ + + /** + * The font mapping as specified in the file fonts.properties. + */ + private static Properties fontProperties; + static + { + fontProperties = new Properties(); + InputStream in = XFontPeer.class.getResourceAsStream("xfonts.properties"); + try + { + fontProperties.load(in); + } + catch (IOException e) + { + e.printStackTrace(); + } + } + + /** + * The FontMetrics implementation for XFontPeer. + */ + private class XFontMetrics + extends FontMetrics + { + /** + * The ascent of the font. + */ + int ascent; + + /** + * The descent of the font. + */ + int descent; + + /** + * The maximum of the character advances. + */ + private int maxAdvance; + + /** + * The internal leading. + */ + int leading; + + /** + * Cached string metrics. This caches string metrics locally so that the + * server doesn't have to be asked each time. + */ + private HashMap metricsCache; + + /** + * The widths of the characters indexed by the characters themselves. + */ + private int[] charWidths; + + /** + * Creates a new XFontMetrics for the specified font. + * + * @param font the font + */ + protected XFontMetrics(Font font) + { + super(font); + metricsCache = new HashMap(); + Fontable.FontInfo info = getXFont().info(); + ascent = info.font_ascent(); + descent = info.font_descent(); + maxAdvance = info.max_bounds().character_width(); + leading = 0; // TODO: Not provided by X. Possible not needed. + + if (info.min_byte1() == 0 && info.max_byte1() == 0) + readCharWidthsLinear(info); + else + readCharWidthsNonLinear(info); + } + + /** + * Reads the character widths when specified in a linear fashion. That is + * when the min-byte1 and max-byte2 fields are both zero in the X protocol. + * + * @param info the font info reply + */ + private void readCharWidthsLinear(Fontable.FontInfo info) + { + int startIndex = info.min_char_or_byte2(); + int endIndex = info.max_char_or_byte2(); + charWidths = new int[endIndex + 1]; + // All the characters before startIndex are zero width. + for (int i = 0; i < startIndex; i++) + { + charWidths[i] = 0; + } + // All the other character info is fetched from the font info. + int index = startIndex; + Fontable.FontInfo.CharInfo[] charInfos = info.char_infos(); + for (Fontable.FontInfo.CharInfo charInfo : charInfos) + { + charWidths[index] = charInfo.character_width(); + index++; + } + } + + private void readCharWidthsNonLinear(Fontable.FontInfo info) + { + // TODO: Implement. + throw new UnsupportedOperationException("Not yet implemented"); + } + + /** + * Returns the ascent of the font. + * + * @return the ascent of the font + */ + public int getAscent() + { + return ascent; + } + + /** + * Returns the descent of the font. + * + * @return the descent of the font + */ + public int getDescent() + { + return descent; + } + + /** + * Returns the overall height of the font. This is the distance from + * baseline to baseline (usually ascent + descent + leading). + * + * @return the overall height of the font + */ + public int getHeight() + { + return ascent + descent; + } + + /** + * Returns the leading of the font. + * + * @return the leading of the font + */ + public int getLeading() + { + return leading; + } + + /** + * Returns the maximum advance for this font. + * + * @return the maximum advance for this font + */ + public int getMaxAdvance() + { + return maxAdvance; + } + + /** + * Determines the width of the specified character c. + * + * @param c the character + * + * @return the width of the character + */ + public int charWidth(char c) + { + int width; + if (c > charWidths.length) + width = charWidths['?']; + else + width = charWidths[c]; + return width; + } + + /** + * Determines the overall width of the specified string. + * + * @param c the char buffer holding the string + * @param offset the starting offset of the string in the buffer + * @param length the number of characters in the string buffer + * + * @return the overall width of the specified string + */ + public int charsWidth(char[] c, int offset, int length) + { + int width = 0; + if (c.length > 0 && length > 0) + { + String s = new String(c, offset, length); + width = stringWidth(s); + } + return width; + } + + /** + * Determines the overall width of the specified string. + * + * @param s the string + * + * @return the overall width of the specified string + */ + public int stringWidth(String s) + { + int width = 0; + if (s.length() > 0) + { + if (metricsCache.containsKey(s)) + { + width = ((Integer) metricsCache.get(s)).intValue(); + } + else + { + Fontable.TextExtentInfo extents = getXFont().text_extent(s); + /* + System.err.println("string: '" + s + "' : "); + System.err.println("ascent: " + extents.getAscent()); + System.err.println("descent: " + extents.getDescent()); + System.err.println("overall ascent: " + extents.getOverallAscent()); + System.err.println("overall descent: " + extents.getOverallDescent()); + System.err.println("overall width: " + extents.getOverallWidth()); + System.err.println("overall left: " + extents.getOverallLeft()); + System.err.println("overall right: " + extents.getOverallRight()); + */ + width = extents.overall_width(); // + extents.overall_left(); + //System.err.println("String: " + s + ", width: " + width); + metricsCache.put(s, new Integer(width)); + } + } + //System.err.print("stringWidth: '" + s + "': "); + //System.err.println(width); + return width; + } + } + + /** + * The LineMetrics implementation for the XFontPeer. + */ + private class XLineMetrics + extends LineMetrics + { + + /** + * Returns the ascent of the font. + * + * @return the ascent of the font + */ + public float getAscent() + { + return fontMetrics.ascent; + } + + public int getBaselineIndex() + { + // FIXME: Implement this. + throw new UnsupportedOperationException(); + } + + public float[] getBaselineOffsets() + { + // FIXME: Implement this. + throw new UnsupportedOperationException(); + } + + /** + * Returns the descent of the font. + * + * @return the descent of the font + */ + public float getDescent() + { + return fontMetrics.descent; + } + + /** + * Returns the overall height of the font. This is the distance from + * baseline to baseline (usually ascent + descent + leading). + * + * @return the overall height of the font + */ + public float getHeight() + { + return fontMetrics.ascent + fontMetrics.descent; + } + + /** + * Returns the leading of the font. + * + * @return the leading of the font + */ + public float getLeading() + { + return fontMetrics.leading; + } + + public int getNumChars() + { + // FIXME: Implement this. + throw new UnsupportedOperationException(); + } + + public float getStrikethroughOffset() + { + return 0.F; // TODO: Provided by X?? + } + + public float getStrikethroughThickness() + { + return 1.F; // TODO: Provided by X?? + } + + public float getUnderlineOffset() + { + return 0.F; // TODO: Provided by X?? + } + + public float getUnderlineThickness() + { + return 1.F; // TODO: Provided by X?? + } + + } + + /** + * The X font. + */ + private gnu.x11.Font xfont; + + private String name; + + private int style; + + private int size; + + /** + * The font metrics for this font. + */ + XFontMetrics fontMetrics; + + /** + * Creates a new XFontPeer for the specified font name, style and size. + * + * @param name the font name + * @param style the font style (bold / italic / normal) + * @param size the size of the font + */ + public XFontPeer(String name, int style, int size) + { + super(name, style, size); + this.name = name; + this.style = style; + this.size = size; + } + + /** + * Creates a new XFontPeer for the specified font name and style + * attributes. + * + * @param name the font name + * @param atts the font attributes + */ + public XFontPeer(String name, Map atts) + { + super(name, atts); + String family = name; + if (family == null || family.equals("")) + family = (String) atts.get(TextAttribute.FAMILY); + if (family == null) + family = "SansSerif"; + + int size = 12; + Float sizeFl = (Float) atts.get(TextAttribute.SIZE); + if (sizeFl != null) + size = sizeFl.intValue(); + + int style = 0; + // Detect italic attribute. + Float posture = (Float) atts.get(TextAttribute.POSTURE); + if (posture != null && !posture.equals(TextAttribute.POSTURE_REGULAR)) + style |= Font.ITALIC; + + // Detect bold attribute. + Float weight = (Float) atts.get(TextAttribute.WEIGHT); + if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0) + style |= Font.BOLD; + + this.name = name; + this.style = style; + this.size = size; + } + + /** + * Initializes the font peer with the specified attributes. This method is + * called from both constructors. + * + * @param name the font name + * @param style the font style + * @param size the font size + */ + private void init(String name, int style, int size) + { + if (name == null) + { + name = "SansSerif"; + } + GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice dev = env.getDefaultScreenDevice(); + if (dev instanceof XGraphicsDevice) + { + Display display = ((XGraphicsDevice) dev).getDisplay(); + String fontDescr = encodeFont(name, style, size); + if (XToolkit.DEBUG) + System.err.println("XLFD font description: " + fontDescr); + xfont = new gnu.x11.Font(display, fontDescr); + } + else + { + throw new AWTError("Local GraphicsEnvironment is not XWindowGraphicsEnvironment"); + } + } + + public boolean canDisplay(Font font, int c) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public int canDisplayUpTo(Font font, CharacterIterator i, int start, int limit) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public String getSubFamilyName(Font font, Locale locale) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public String getPostScriptName(Font font) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public int getNumGlyphs(Font font) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public int getMissingGlyphCode(Font font) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public byte getBaselineFor(Font font, char c) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public String getGlyphName(Font font, int glyphIndex) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GlyphVector createGlyphVector(Font font, FontRenderContext frc, + CharacterIterator ci) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GlyphVector createGlyphVector(Font font, FontRenderContext ctx, + int[] glyphCodes) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GlyphVector layoutGlyphVector(Font font, FontRenderContext frc, + char[] chars, int start, int limit, + int flags) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Returns the font metrics for the specified font. + * + * @param font the font for which to fetch the font metrics + * + * @return the font metrics for the specified font + */ + public FontMetrics getFontMetrics(Font font) + { + if (font.getPeer() != this) + throw new AWTError("The specified font has a different peer than this"); + + if (fontMetrics == null) + fontMetrics = new XFontMetrics(font); + return fontMetrics; + } + + /** + * Frees the font in the X server. + */ + protected void finalize() + { + if (xfont != null) + xfont.close(); + } + + public boolean hasUniformLineMetrics(Font font) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Returns the line metrics for this font and the specified string and + * font render context. + */ + public LineMetrics getLineMetrics(Font font, CharacterIterator ci, int begin, + int limit, FontRenderContext rc) + { + return new XLineMetrics(); + } + + public Rectangle2D getMaxCharBounds(Font font, FontRenderContext rc) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Rectangle2D getStringBounds(Font font, CharacterIterator ci, + int begin, int limit, FontRenderContext frc) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Encodes a font name + style + size specification into a X logical font + * description (XLFD) as described here: + * + * http://www.meretrx.com/e93/docs/xlfd.html + * + * This is implemented to look up the font description in the + * fonts.properties of this package. + * + * @param name the font name + * @param atts the text attributes + * + * @return the encoded font description + */ + static String encodeFont(String name, Map atts) + { + String family = name; + if (family == null || family.equals("")) + family = (String) atts.get(TextAttribute.FAMILY); + if (family == null) + family = "SansSerif"; + + int size = 12; + Float sizeFl = (Float) atts.get(TextAttribute.SIZE); + if (sizeFl != null) + size = sizeFl.intValue(); + + int style = 0; + // Detect italic attribute. + Float posture = (Float) atts.get(TextAttribute.POSTURE); + if (posture != null && !posture.equals(TextAttribute.POSTURE_REGULAR)) + style |= Font.ITALIC; + + // Detect bold attribute. + Float weight = (Float) atts.get(TextAttribute.WEIGHT); + if (weight != null && weight.compareTo(TextAttribute.WEIGHT_REGULAR) > 0) + style |= Font.BOLD; + + return encodeFont(family, style, size); + } + + /** + * Encodes a font name + style + size specification into a X logical font + * description (XLFD) as described here: + * + * http://www.meretrx.com/e93/docs/xlfd.html + * + * This is implemented to look up the font description in the + * fonts.properties of this package. + * + * @param name the font name + * @param style the font style + * @param size the font size + * + * @return the encoded font description + */ + static String encodeFont(String name, int style, int size) + { + CPStringBuilder key = new CPStringBuilder(); + key.append(validName(name)); + key.append('.'); + switch (style) + { + case Font.BOLD: + key.append("bold"); + break; + case Font.ITALIC: + key.append("italic"); + break; + case (Font.BOLD | Font.ITALIC): + key.append("bolditalic"); + break; + case Font.PLAIN: + default: + key.append("plain"); + + } + + String protoType = fontProperties.getProperty(key.toString()); + int s = validSize(size); + return protoType.replaceFirst("%d", String.valueOf(s)); + } + + /** + * Checks the specified font name for a valid font name. If the font name + * is not known, then this returns 'sansserif' as fallback. + * + * @param name the font name to check + * + * @return a valid font name + */ + static String validName(String name) + { + String retVal; + if (name.equalsIgnoreCase("sansserif") + || name.equalsIgnoreCase("serif") + || name.equalsIgnoreCase("monospaced") + || name.equalsIgnoreCase("dialog") + || name.equalsIgnoreCase("dialoginput")) + { + retVal = name.toLowerCase(); + } + else + { + retVal = "sansserif"; + } + return retVal; + } + + /** + * Translates an arbitrary point size to a size that is typically available + * on an X server. These are the sizes 8, 10, 12, 14, 18 and 24. + * + * @param size the queried size + * @return the real available size + */ + private static final int validSize(int size) + { + int val; + if (size <= 9) + val = 8; + else if (size <= 11) + val = 10; + else if (size <= 13) + val = 12; + else if (size <= 17) + val = 14; + else if (size <= 23) + val = 18; + else + val = 24; + return val; + } + + /** + * Returns the X Font reference. This lazily loads the font when first + * requested. + * + * @return the X Font reference + */ + gnu.x11.Font getXFont() + { + if (xfont == null) + { + init(name, style, size); + } + return xfont; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XFramePeer.java b/libjava/classpath/gnu/java/awt/peer/x/XFramePeer.java new file mode 100644 index 000000000..cde67778d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XFramePeer.java @@ -0,0 +1,145 @@ +/* XFramePeer.java -- The X FramePeer implementation + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.x; + +import java.awt.Component; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Insets; +import java.awt.MenuBar; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; +import java.awt.peer.FramePeer; + +import gnu.java.awt.peer.swing.SwingFramePeer; +import gnu.x11.Window; +import gnu.x11.event.Event; + +public class XFramePeer + extends XWindowPeer + implements FramePeer +{ + + XFramePeer(Frame f) + { + super(f); + setTitle(f.getTitle()); + } + + public void setIconImage(Image image) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void setMenuBar(MenuBar mb) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void setResizable(boolean resizable) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void setTitle(String title) + { + xwindow.set_wm_name (title); + } + + public int getState() + { + return 0; + } + + public void setState(int state) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void setMaximizedBounds(Rectangle r) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Check if this frame peer supports being restacked. + * + * @return true if this frame peer can be restacked, + * false otherwise + * @since 1.5 + */ + public boolean isRestackSupported() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Sets the bounds of this frame peer. + * + * @param x the new x co-ordinate + * @param y the new y co-ordinate + * @param width the new width + * @param height the new height + * @since 1.5 + */ + public void setBoundsPrivate(int x, int y, int width, int height) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Rectangle getBoundsPrivate() + { + // TODO: Implement this properly. + throw new InternalError("Not yet implemented"); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XGraphics2D.java b/libjava/classpath/gnu/java/awt/peer/x/XGraphics2D.java new file mode 100644 index 000000000..1fce2dcf7 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XGraphics2D.java @@ -0,0 +1,508 @@ +/* XGraphics2D.java -- A Java based Graphics2D impl for X + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.x; + +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Image; +import java.awt.Paint; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.Toolkit; +import java.awt.Transparency; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DataBuffer; +import java.awt.image.ImageObserver; +import java.awt.image.Raster; +import java.awt.peer.FontPeer; +import java.util.HashMap; +import java.util.WeakHashMap; + +import gnu.java.awt.image.AsyncImage; +import gnu.java.awt.java2d.AbstractGraphics2D; +import gnu.java.awt.java2d.ScanlineCoverage; +import gnu.x11.Colormap; +import gnu.x11.Drawable; +import gnu.x11.GC; +import gnu.x11.image.ZPixmap; + +public class XGraphics2D + extends AbstractGraphics2D +{ + + /** + * When this property is set to true, then images are always rendered as + * opaque images, ignoring their translucence. This is intended for + * debugging and demonstration purposes. + */ + private static final boolean RENDER_OPAQUE = + Boolean.getBoolean("escherpeer.renderopaque"); + + /** + * The X Drawable to draw on. + */ + private Drawable xdrawable; + + /** + * The X graphics context (GC). + */ + private GC xgc; + + /** + * Indicates if this graphics has already been disposed. + */ + private boolean disposed; + + /** + * The current foreground color, possibly null. + */ + private Color foreground; + + XGraphics2D(Drawable d) + { + super(); + xdrawable = d; + xgc = new GC(d); + init(); + disposed = false; + //setClip(new Rectangle(0, 0, xdrawable.width, xdrawable.height)); + } + + @Override + protected void rawDrawLine(int x0, int y0, int x1, int y1) + { + xdrawable.segment(xgc, x0, y0, x1, y1); + } + + @Override + protected void rawDrawRect(int x, int y, int w, int h) + { + xdrawable.rectangle(xgc, x, y, w, h, false); + } + + @Override + protected void rawFillRect(int x, int y, int w, int h) + { + xdrawable.rectangle(xgc, x, y, w, h, true); + } + + /** + * Returns the color model of this Graphics object. + * + * @return the color model of this Graphics object + */ + protected ColorModel getColorModel() + { + return Toolkit.getDefaultToolkit().getColorModel(); + } + + /** + * Returns the color model of the target device. + * + * @return the color model of the target device + */ + protected ColorModel getDestinationColorModel() + { + return Toolkit.getDefaultToolkit().getColorModel(); + } + + /** + * Returns the bounds of the target. + * + * @return the bounds of the target + */ + protected Rectangle getDeviceBounds() + { + return new Rectangle(0, 0, xdrawable.width, xdrawable.height); + } + + public GraphicsConfiguration getDeviceConfiguration() + { + // FIXME: Implement this. + throw new UnsupportedOperationException("Not yet implemented"); + } + + public void dispose() + { + if (!disposed) + { + xgc.free(); + xdrawable.display.flush(); + disposed = true; + } + } + + public Graphics create() + { + // super.create() returns a copy created by clone(), so it should + // be a XGraphics2D. + XGraphics2D copy = (XGraphics2D) super.create(); + copy.xgc = xgc.copy(); + return copy; + } + + public void setClip(Shape c) + { + super.setClip(c); + if (c instanceof Rectangle) + { + Rectangle r = (Rectangle) c; + AffineTransform t = getTransform(); + int translateX = (int) t.getTranslateX(); + //System.err.println("translateX: " + translateX); + int translateY = (int) t.getTranslateY(); + //System.err.println("translateY: " + translateY); + //System.err.println("clip: " + c); + gnu.x11.Rectangle clip = new gnu.x11.Rectangle(r.x, r.y, r.width, + r.height); + xgc.set_clip_rectangles(translateX, translateY, + new gnu.x11.Rectangle[]{clip}, GC.UN_SORTED); + } + } + + /** + * Notifies the backend that the raster has changed in the specified + * rectangular area. The raster that is provided in this method is always + * the same as the one returned in {@link #getDestinationRaster}. + * Backends that reflect changes to this raster directly don't need to do + * anything here. + * + * @param raster the updated raster, identical to the raster returned + * by {@link #getDestinationRaster()} + * @param x the upper left corner of the updated region, X coordinate + * @param y the upper lef corner of the updated region, Y coordinate + * @param w the width of the updated region + * @param h the height of the updated region + */ + protected void updateRaster(Raster raster, int x, int y, int w, int h) + { + if (w > 0 && h > 0) + { + ZPixmap zPixmap = new ZPixmap(xdrawable.display, w, h, + xdrawable.display.default_pixmap_format); + int[] pixel = null; + int x1 = x + w; + int y1 = y + h; + for (int tx = x; tx < x1; tx++) + { + for (int ty = y; ty < y1; ty++) + { + pixel = raster.getPixel(tx, ty, pixel); + //System.err.println("tx: " + tx + ", ty: " + ty + ", pixel: " + pixel[0] + ", " + pixel[1] + ", " + pixel[2]); +// System.err.print("r: " + pixel[0]); +// System.err.print(", g: " + pixel[1]); +// System.err.println(", b: " + pixel[2]); + zPixmap.set_red(tx - x, ty - y, pixel[0]); + zPixmap.set_green(tx - x, ty - y, pixel[1]); + zPixmap.set_blue(tx - x, ty - y, pixel[2]); + } + } + xdrawable.put_image(xgc, zPixmap, x, y); + } + } + + @Override + public void renderScanline(int y, ScanlineCoverage c) + { + if (y >= xdrawable.height) + return; + + // TODO: Handle Composite and Paint. + ScanlineCoverage.Iterator iter = c.iterate(); + int coverageAlpha = 0; + int maxCoverage = c.getMaxCoverage(); + while (iter.hasNext()) + { + ScanlineCoverage.Range range = iter.next(); + + coverageAlpha = range.getCoverage(); + int x0 = range.getXPos(); + int l = range.getLength(); + if (coverageAlpha == c.getMaxCoverage()) + { + // Simply paint the current color over the existing pixels. + xdrawable.fill_rectangle(xgc, x0, y, l, 1); + } + else if (coverageAlpha > 0) + { + // Composite the current color with the existing pixels. + int x1 = x0 + l; + x0 = Math.min(Math.max(0, x0), xdrawable.width - 1); + x1 = Math.min(Math.max(0, x1), xdrawable.width - 1); + if ((x1 - x0) < 1) + continue; + l = x1 - x0; + gnu.x11.image.ZPixmap existing = (ZPixmap) + xdrawable.image(x0, y, l, 1, 0xFFFFFFFF, + gnu.x11.image.Image.Format.ZPIXMAP); + for (int x = 0; x < l; x++) + { + Color col = getColor(); + if (col == null) + { + col = Color.BLACK; + } + int red = col.getRed(); + int green = col.getGreen(); + int blue = col.getBlue(); + int redOut = existing.get_red(x, 0); + int greenOut = existing.get_green(x, 0); + int blueOut = existing.get_blue(x, 0); + int outAlpha = maxCoverage - coverageAlpha; + redOut = redOut * outAlpha + red * coverageAlpha; + redOut = redOut / maxCoverage; + greenOut = greenOut * outAlpha + green * coverageAlpha; + greenOut = greenOut / maxCoverage; + blueOut = blueOut * outAlpha + blue * coverageAlpha; + blueOut = blueOut / maxCoverage; + existing.set(x, 0, redOut, greenOut, blueOut); + } + xdrawable.put_image(xgc, existing, x0, y); + } + } + } + + protected void init() + { + super.init(); + } + + public void setPaint(Paint p) + { + super.setPaint(p); + if (p instanceof Color) + { + // TODO: Optimize for different standard bit-depths. + Color c = (Color) p; + /* XToolkit tk = (XToolkit) Toolkit.getDefaultToolkit(); + HashMap colorMap = tk.colorMap; + gnu.x11.Color col = (gnu.x11.Color) colorMap.get(c); + if (col == null) + { + Colormap map = xdrawable.display.default_colormap; + col = map.alloc_color (c.getRed() * 256, + c.getGreen() * 256, + c.getBlue() * 256); + colorMap.put(c, col); + }*/ + //xgc.set_foreground(col); + + xgc.set_foreground(c.getRGB()); + foreground = c; + } + } + + protected void fillShape(Shape s, boolean isFont) + { + synchronized (xdrawable.display) { + super.fillShape(s, isFont); + } + } + + private static WeakHashMap imageCache = new WeakHashMap(); + + protected boolean rawDrawImage(Image image, int x, int y, ImageObserver obs) + { + image = unwrap(image); + boolean ret; + if (image instanceof XImage) + { + XImage xImage = (XImage) image; + xdrawable.copy_area(xImage.pixmap, xgc, 0, 0, xImage.getWidth(obs), + xImage.getHeight(obs), x, y); + ret = true; + } + else if (image instanceof PixmapVolatileImage) + { + PixmapVolatileImage pvi = (PixmapVolatileImage) image; + xdrawable.copy_area(pvi.getPixmap(), xgc, 0, 0, pvi.getWidth(obs), + pvi.getHeight(obs), x, y); + ret = true; + } + else if (image instanceof BufferedImage) + { + BufferedImage bi = (BufferedImage) image; + DataBuffer db = bi.getRaster().getDataBuffer(); + if (db instanceof ZPixmapDataBuffer) + { + ZPixmapDataBuffer zpmdb = (ZPixmapDataBuffer) db; + ZPixmap zpixmap = zpmdb.getZPixmap(); + xdrawable.put_image(xgc, zpixmap, x, y); + ret = true; + } + else + { + int transparency = bi.getTransparency(); + int w = bi.getWidth(); + int h = bi.getHeight(); + if (imageCache.containsKey(image)) + { + ZPixmap zpixmap = imageCache.get(image); + xdrawable.put_image(xgc, zpixmap, x, y); + } + else if (transparency == Transparency.OPAQUE || RENDER_OPAQUE) + { + XGraphicsDevice gd = XToolkit.getDefaultDevice(); + ZPixmap zpixmap = new ZPixmap(gd.getDisplay(), w, h); + for (int yy = 0; yy < h; yy++) + { + for (int xx = 0; xx < w; xx++) + { + int rgb = bi.getRGB(xx, yy); + zpixmap.set(xx, yy, rgb); + } + } + xdrawable.put_image(xgc, zpixmap, x, y); + imageCache.put(image, zpixmap); + } else { + + // TODO optimize reusing the rectangles + Rectangle source = + new Rectangle(0, 0, xdrawable.width, xdrawable.height); + Rectangle target = new Rectangle(x, y, w, h); + + Rectangle destination = source.intersection(target); + + x = destination.x; + y = destination.y; + w = destination.width; + h = destination.height; + + ZPixmap zpixmap = + (ZPixmap) xdrawable.image(x, y, w, h, + 0xffffffff, + gnu.x11.image.Image.Format.ZPIXMAP); + for (int yy = 0; yy < h; yy++) + { + for (int xx = 0; xx < w; xx++) + { + int rgb = bi.getRGB(xx, yy); + int alpha = 0xff & (rgb >> 24); + if (alpha == 0) + { + // Completely translucent. + rgb = zpixmap.get_red(xx, yy) << 16 + | zpixmap.get_green(xx, yy) << 8 + | zpixmap.get_blue(xx, yy); + } + else if (alpha < 255) + { + // Composite pixels. + int red = 0xff & (rgb >> 16); + red = red * alpha + + (255 - alpha) * zpixmap.get_red(xx, yy); + red = red / 255; + int green = 0xff & (rgb >> 8); + green = green * alpha + + (255 - alpha) * zpixmap.get_green(xx, yy); + green = green / 255; + int blue = 0xff & rgb; + blue = blue * alpha + + (255 - alpha) * zpixmap.get_blue(xx, yy); + blue = blue / 255; + rgb = red << 16 | green << 8 | blue; + } + // else keep rgb value from source image. + + zpixmap.set(xx, yy, rgb); + } + } + xdrawable.put_image(xgc, zpixmap, x, y); + // We can't cache prerendered translucent images, because + // we never know how the background changes. + } + ret = true; + } + } + else + { + ret = super.rawDrawImage(image, x, y, obs); + } + return ret; + } + + public void setFont(Font f) + { + super.setFont(f); + FontPeer p = getFont().getPeer(); + if (p instanceof XFontPeer) + { + XFontPeer xFontPeer = (XFontPeer) p; + xgc.set_font(xFontPeer.getXFont()); + } + } + + public void drawString(String s, int x, int y) + { + FontPeer p = getFont().getPeer(); + if (p instanceof XFontPeer) + { + int tx = (int) transform.getTranslateX(); + int ty = (int) transform.getTranslateY(); + xdrawable.text(xgc, x + tx, y + ty, s); + } + else + { + super.drawString(s, x, y); + } + } + + /** + * Extracts an image instance out of an AsyncImage. If the image isn't + * an AsyncImage, then the original instance is returned. + * + * @param im the image + * + * @return the image to render + */ + private Image unwrap(Image im) + { + Image image = im; + if (image instanceof AsyncImage) + { + AsyncImage aIm = (AsyncImage) image; + image = aIm.getRealImage(); + } + return image; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XGraphicsConfiguration.java b/libjava/classpath/gnu/java/awt/peer/x/XGraphicsConfiguration.java new file mode 100644 index 000000000..aed11a3af --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XGraphicsConfiguration.java @@ -0,0 +1,200 @@ +/* XGraphicsConfiguration.java -- GraphicsConfiguration for X + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.x; + +import gnu.x11.Display; +import gnu.x11.Screen; + +import java.awt.Dimension; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.Transparency; +import java.awt.color.ColorSpace; +import java.awt.geom.AffineTransform; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.ComponentColorModel; +import java.awt.image.ComponentSampleModel; +import java.awt.image.DataBuffer; +import java.awt.image.Raster; +import java.awt.image.SampleModel; +import java.awt.image.VolatileImage; +import java.awt.image.WritableRaster; + +public class XGraphicsConfiguration + extends GraphicsConfiguration +{ + + XGraphicsDevice device; + + XGraphicsConfiguration(XGraphicsDevice dev) + { + device = dev; + } + + public GraphicsDevice getDevice() + { + return device; + } + + public BufferedImage createCompatibleImage(int w, int h) + { + return createCompatibleImage(w, h, Transparency.OPAQUE); + } + + public BufferedImage createCompatibleImage(int w, int h, int transparency) + { + BufferedImage bi; + switch (transparency) + { + case Transparency.OPAQUE: + DataBuffer buffer = new ZPixmapDataBuffer(w, h); + SampleModel sm = new ComponentSampleModel(DataBuffer.TYPE_BYTE, w, h, + 4, w * 4, + new int[]{0, 1, 2, 3 }); + ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_LINEAR_RGB); + ColorModel cm = new ComponentColorModel(cs, true, false, + Transparency.OPAQUE, + DataBuffer.TYPE_BYTE); + WritableRaster raster = Raster.createWritableRaster(sm, buffer, + new Point(0, 0)); + bi = new BufferedImage(cm, raster, false, null); + break; + case Transparency.BITMASK: + case Transparency.TRANSLUCENT: + bi = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); + break; + default: + throw new IllegalArgumentException("Illegal transparency: " + + transparency); + } + return bi; + } + + public VolatileImage createCompatibleVolatileImage(int w, int h) + { + return createCompatibleVolatileImage(w, h, Transparency.OPAQUE); + } + + public VolatileImage createCompatibleVolatileImage(int width, int height, + int transparency) + { + VolatileImage im; + switch (transparency) + { + case Transparency.OPAQUE: + im = new PixmapVolatileImage(width, height); + break; + case Transparency.BITMASK: + case Transparency.TRANSLUCENT: + throw new UnsupportedOperationException("Not yet implemented"); + default: + throw new IllegalArgumentException("Unknown transparency type: " + + transparency); + } + return im; + } + + public ColorModel getColorModel() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public ColorModel getColorModel(int transparency) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public AffineTransform getDefaultTransform() + { + return new AffineTransform(); + } + + public AffineTransform getNormalizingTransform() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Rectangle getBounds() + { + Display d = device.getDisplay(); + Screen screen = d.default_screen; + + return new Rectangle(0, 0, screen.width, screen.height); + } + + /** + * Determines the size of the primary screen. + * + * @return the size of the primary screen + */ + Dimension getSize() + { + // TODO: A GraphicsConfiguration should correspond to a Screen instance. + Display d = device.getDisplay(); + Screen screen = d.default_screen; + int w = screen.width; + int h = screen.height; + return new Dimension(w, h); + } + + /** + * Determines the resolution of the primary screen in pixel-per-inch. + * + * @returnthe resolution of the primary screen in pixel-per-inch + */ + int getResolution() + { + Display d = device.getDisplay(); + Screen screen = d.default_screen; + int w = screen.width * 254; + int h = screen.height * 254; + int wmm = screen.width_in_mm * 10; + int hmm = screen.height_in_mm * 10; + int xdpi = w / wmm; + int ydpi = h / hmm; + int dpi = (xdpi + ydpi) / 2; + return dpi; + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XGraphicsDevice.java b/libjava/classpath/gnu/java/awt/peer/x/XGraphicsDevice.java new file mode 100644 index 000000000..6b65e14ed --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XGraphicsDevice.java @@ -0,0 +1,200 @@ +/* XGraphicsDevice.java -- GraphicsDevice for X + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.peer.x; + +import gnu.classpath.SystemProperties; +import gnu.x11.Display; +import gnu.x11.EscherServerConnectionException; + +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.lang.reflect.Constructor; +import java.net.Socket; + +/** + * This class represents an X Display. The actual connection is established + * lazily when it is first needed. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class XGraphicsDevice + extends GraphicsDevice +{ + + private XGraphicsConfiguration defaultConfiguration; + + /** + * The X display associated with the XGraphicsDevice. This is established + * when {@link #getDisplay} is first called. + */ + private Display display; + + /** + * The display name from which the display will be initialized. + */ + private Display.Name displayName; + + /** + * The event pump for this X Display. + */ + private XEventPump eventPump; + + /** + * Creates a new XGraphicsDevice. + */ + XGraphicsDevice(Display.Name dn) + { + displayName = dn; + } + + public int getType() + { + return TYPE_RASTER_SCREEN; + } + + public String getIDstring() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GraphicsConfiguration[] getConfigurations() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public GraphicsConfiguration getDefaultConfiguration() + { + if (defaultConfiguration == null) + defaultConfiguration = new XGraphicsConfiguration(this); + return defaultConfiguration; + } + + /** + * Returns the X Display associated with this XGraphicsDevice. + * This establishes the connection to the X server on the first invocation. + * + * @return the X Display associated with this XGraphicsDevice + */ + Display getDisplay() + { + if (display == null) + { + if (displayName.hostname.equals("")) + displayName.hostname = "localhost"; + if (XToolkit.DEBUG) + System.err.println("connecting to : " + displayName); + // Try to connect via unix domain sockets when host == localhost. + if ((displayName.hostname.equals("localhost") + || displayName.hostname.equals("")) + && SystemProperties.getProperty("gnu.xawt.no_local_sockets") == null) + { + Socket socket = createLocalSocket(); + if (socket != null) + { + try + { + display = new Display(socket, "localhost", + displayName.display_no, + displayName.screen_no); + } + catch (EscherServerConnectionException e) + { + throw new RuntimeException(e.getCause()); + } + } + } + + // The following happens when we are configured to use plain sockets, + // when the connection is probably remote or when we couldn't load + // the LocalSocket class stuff. + if (display == null) + { + try + { + display = new Display(displayName); + } + catch (EscherServerConnectionException e) + { + throw new RuntimeException(e.getCause()); + } + } + + eventPump = new XEventPump(display); + } + return display; + } + + XEventPump getEventPump() + { + return eventPump; + } + + /** + * Tries to load the LocalSocket class and initiate a connection to the + * local X server. + */ + private Socket createLocalSocket() + { + Socket socket = null; + try + { + // TODO: Is this 100% ok? + String sockPath = "/tmp/.X11-unix/X" + displayName.display_no; + Class localSocketAddressClass = + Class.forName("gnu.java.net.local.LocalSocketAddress"); + Constructor localSocketAddressConstr = + localSocketAddressClass.getConstructor(new Class[]{ String.class }); + Object addr = + localSocketAddressConstr.newInstance(new Object[]{ sockPath }); + Class localSocketClass = + Class.forName("gnu.java.net.local.LocalSocket"); + Constructor localSocketConstructor = + localSocketClass.getConstructor(new Class[]{localSocketAddressClass}); + Object localSocket = + localSocketConstructor.newInstance(new Object[]{ addr }); + socket = (Socket) localSocket; + } + catch (Exception ex) + { + // Whatever goes wrong here, we return null. + } + return socket; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XGraphicsEnvironment.java b/libjava/classpath/gnu/java/awt/peer/x/XGraphicsEnvironment.java new file mode 100644 index 000000000..7b1d82fee --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XGraphicsEnvironment.java @@ -0,0 +1,203 @@ +/* XGraphicsEnvironment.java -- Represents the X environment + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.x; + +import gnu.java.awt.font.OpenTypeFontPeer; +import gnu.java.awt.java2d.RasterGraphics; +import gnu.x11.Display; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.image.BufferedImage; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Locale; +import java.util.Properties; + +/** + * Represents the X environment for AWT. + * + * @author Roman Kennke (kennke@aicas.com) + */ +public class XGraphicsEnvironment + extends GraphicsEnvironment +{ + + /** + * The default graphics device. This is normally the local main X + * Display, but can be configured to be any X connection. + */ + private XGraphicsDevice defaultDevice; + + /** + * All configured devices. + */ + private XGraphicsDevice[] devices; + + /** + * Creates a new XGraphicsEnvironment. This loads the configuration if + * there is one present and initializes the XGraphicsDevices in the + * environment. If there is no configuration, then there is one + * default device initialized with the local main X device. + */ + public XGraphicsEnvironment() + { + // Initiliaze the devices. + Properties props = new Properties(); + File config = new File(System.getProperty("user.home"), + ".xawt.properties"); + + try + { + FileInputStream configIn = new FileInputStream(config); + props.load(configIn); + int dev = 1; + ArrayList deviceList = new ArrayList(); + while (true) + { + String propName = "display." + dev; + String propValue = props.getProperty(propName); + if (propValue != null) + { + Display.Name displayName = new Display.Name(propValue); + XGraphicsDevice device = new XGraphicsDevice(displayName); + if (dev == 1) + defaultDevice = device; + deviceList.add(device); + dev++; + } + else + { + if (dev == 1) + { + defaultDevice = initDefaultDevice(); + deviceList.add(defaultDevice); + } + break; + } + } + devices = (XGraphicsDevice[]) deviceList.toArray + (new XGraphicsDevice[deviceList.size()]); + } + catch (FileNotFoundException ex) + { + defaultDevice = initDefaultDevice(); + devices = new XGraphicsDevice[]{ defaultDevice }; + } + catch (IOException ex) + { + defaultDevice = initDefaultDevice(); + devices = new XGraphicsDevice[]{ defaultDevice }; + } + + } + + /** + * Helper method that initializes the default device in the case when there + * is no configuration for the default. + */ + private XGraphicsDevice initDefaultDevice() + { + String display = System.getenv("DISPLAY"); + if (display == null) + display = ":0.0"; + Display.Name displayName = new Display.Name(display); + return new XGraphicsDevice(displayName); + } + + /** + * Returns all configured screen devices. + * + * @return all configured screen devices + */ + public GraphicsDevice[] getScreenDevices() + { + // We return a copy so that nobody can fiddle with our devices. + XGraphicsDevice[] copy = new XGraphicsDevice[devices.length]; + System.arraycopy(devices, 0, copy, 0, devices.length); + return copy; + } + + /** + * Returns the default screen device. + * + * @return the default screen device + */ + public GraphicsDevice getDefaultScreenDevice() + { + return defaultDevice; + } + + /** + * Returns a Graphics instance suitable for drawing on top of the + * BufferedImage. + * + * @param image the buffered image to create a graphics for + * + * @return a Graphics2D instance for drawing on the BufferedImage + */ + public Graphics2D createGraphics(BufferedImage image) + { + return new RasterGraphics(image.getRaster(), image.getColorModel()); + } + + public Font[] getAllFonts() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public String[] getAvailableFontFamilyNames() + { + return getAvailableFontFamilyNames(Locale.getDefault()); + } + + public String[] getAvailableFontFamilyNames(Locale l) + { + // TODO: This doesn't work when we are using X fonts. + // Fix this. + return OpenTypeFontPeer.getAvailableFontFamilyNames(l); + } + +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XImage.java b/libjava/classpath/gnu/java/awt/peer/x/XImage.java new file mode 100644 index 000000000..f3df89f4d --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XImage.java @@ -0,0 +1,178 @@ +/* XImage.java -- Image impl for X Pixmaps + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.x; + +import gnu.x11.Pixmap; +import gnu.x11.image.ZPixmap; + +import java.awt.Graphics; +import java.awt.GraphicsEnvironment; +import java.awt.Image; + +import java.awt.image.ColorModel; +import java.awt.image.ImageConsumer; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; + +import java.util.Hashtable; +import java.util.Vector; + +public class XImage + extends Image +{ + + Pixmap pixmap; + + private Hashtable properties; + + XImage(int w, int h) + { + GraphicsEnvironment env = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + XGraphicsDevice dev = (XGraphicsDevice) env.getDefaultScreenDevice(); + pixmap = new Pixmap(dev.getDisplay(), w, h); + } + + public int getWidth(ImageObserver observer) + { + return pixmap.width; + } + + public int getHeight(ImageObserver observer) + { + return pixmap.height; + } + + public ImageProducer getSource() + { + return new XImageProducer(); + } + + /** + * Creates an XGraphics for drawing on this XImage. + * + * @return an XGraphics for drawing on this XImage + */ + public Graphics getGraphics() + { + XGraphics2D g = new XGraphics2D(pixmap); + return g; + } + + public Object getProperty(String name, ImageObserver observer) + { + Object val = null; + if (properties != null) + val = properties.get(val); + return val; + } + + public void flush() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected void finalize() + { + pixmap.free(); + } + + protected class XImageProducer implements ImageProducer + { + private Vector consumers = new Vector(); + + public void addConsumer(ImageConsumer ic) + { + if (ic != null && !isConsumer(ic)) + this.consumers.add(ic); + } + + public boolean isConsumer(ImageConsumer ic) + { + return this.consumers.contains(ic); + } + + public void removeConsumer(ImageConsumer ic) + { + if (ic != null) + this.consumers.remove(ic); + } + + public void requestTopDownLeftRightResend(ImageConsumer ic) + { + /* just ignore the call */ + } + + public void startProduction(ImageConsumer ic) + { + this.addConsumer(ic); + + for (ImageConsumer consumer : this.consumers) + { + int width = XImage.this.getWidth(null); + int height = XImage.this.getHeight(null); + + XGraphics2D graphics = (XGraphics2D) getGraphics(); + ColorModel model = graphics.getColorModel(); + graphics.dispose(); + + ZPixmap zpixmap = (ZPixmap) + XImage.this.pixmap.image(0, 0, width, height, + 0xffffffff, + gnu.x11.image.Image.Format.ZPIXMAP); + + int size = zpixmap.get_data_length(); + System.out.println("size: " + size + ", w = " + width + ", h = " + height); + + int [] pixel = new int[size]; + for (int i = 0; i < size; i++) + pixel[i] = zpixmap.get_data_element(i); + + consumer.setHints(ImageConsumer.SINGLEPASS); + + consumer.setDimensions(width, height); + consumer.setPixels(0, 0, width, height, model, pixel, 0, width); + consumer.imageComplete(ImageConsumer.STATICIMAGEDONE); + } + + System.out.println("done!"); + } + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XToolkit.java b/libjava/classpath/gnu/java/awt/peer/x/XToolkit.java new file mode 100644 index 000000000..a3eeb0f53 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XToolkit.java @@ -0,0 +1,667 @@ +/* XToolkit.java -- The central AWT Toolkit for the X peers + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.x; + +import java.awt.AWTException; +import java.awt.Button; +import java.awt.Canvas; +import java.awt.Checkbox; +import java.awt.CheckboxMenuItem; +import java.awt.Choice; +import java.awt.Dialog; +import java.awt.Dimension; +import java.awt.EventQueue; +import java.awt.FileDialog; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.HeadlessException; +import java.awt.Image; +import java.awt.Label; +import java.awt.List; +import java.awt.Menu; +import java.awt.MenuBar; +import java.awt.MenuItem; +import java.awt.Panel; +import java.awt.PopupMenu; +import java.awt.PrintJob; +import java.awt.ScrollPane; +import java.awt.Scrollbar; +import java.awt.TextArea; +import java.awt.TextField; +import java.awt.Transparency; +import java.awt.Window; +import java.awt.Dialog.ModalExclusionType; +import java.awt.Dialog.ModalityType; +import java.awt.datatransfer.Clipboard; +import java.awt.dnd.DragGestureEvent; +import java.awt.dnd.peer.DragSourceContextPeer; +import java.awt.im.InputMethodHighlight; +import java.awt.image.BufferedImage; +import java.awt.image.ColorModel; +import java.awt.image.DirectColorModel; +import java.awt.image.ImageObserver; +import java.awt.image.ImageProducer; +import java.awt.peer.ButtonPeer; +import java.awt.peer.CanvasPeer; +import java.awt.peer.CheckboxMenuItemPeer; +import java.awt.peer.CheckboxPeer; +import java.awt.peer.ChoicePeer; +import java.awt.peer.DialogPeer; +import java.awt.peer.FileDialogPeer; +import java.awt.peer.FontPeer; +import java.awt.peer.FramePeer; +import java.awt.peer.LabelPeer; +import java.awt.peer.ListPeer; +import java.awt.peer.MenuBarPeer; +import java.awt.peer.MenuItemPeer; +import java.awt.peer.MenuPeer; +import java.awt.peer.PanelPeer; +import java.awt.peer.PopupMenuPeer; +import java.awt.peer.RobotPeer; +import java.awt.peer.ScrollPanePeer; +import java.awt.peer.ScrollbarPeer; +import java.awt.peer.TextAreaPeer; +import java.awt.peer.TextFieldPeer; +import java.awt.peer.WindowPeer; +import java.io.ByteArrayInputStream; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; +import java.util.WeakHashMap; + +import javax.imageio.ImageIO; + +import gnu.classpath.SystemProperties; +import gnu.java.awt.ClasspathToolkit; +import gnu.java.awt.EmbeddedWindow; +import gnu.java.awt.font.OpenTypeFontPeer; +import gnu.java.awt.image.ImageConverter; +import gnu.java.awt.java2d.AbstractGraphics2D; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.peer.EmbeddedWindowPeer; +import gnu.java.awt.peer.swing.SwingButtonPeer; +import gnu.java.awt.peer.swing.SwingCanvasPeer; +import gnu.java.awt.peer.swing.SwingCheckboxPeer; +import gnu.java.awt.peer.swing.SwingLabelPeer; +import gnu.java.awt.peer.swing.SwingPanelPeer; +import gnu.java.awt.peer.swing.SwingTextAreaPeer; +import gnu.java.awt.peer.swing.SwingTextFieldPeer; + +public class XToolkit + extends ClasspathToolkit +{ + + /** + * Set to true to enable debug output. + */ + static boolean DEBUG = false; + + /** + * Maps AWT colors to X colors. + */ + HashMap colorMap = new HashMap(); + + /** + * The system event queue. + */ + private EventQueue eventQueue; + + /** + * The default color model of this toolkit. + */ + private ColorModel colorModel; + + /** + * Maps image URLs to Image instances. + */ + private HashMap imageCache = new HashMap(); + + /** + * The cached fonts. + */ + private WeakHashMap fontCache = + new WeakHashMap(); + + public XToolkit() + { + SystemProperties.setProperty("gnu.javax.swing.noGraphics2D", "true"); + SystemProperties.setProperty("java.awt.graphicsenv", + "gnu.java.awt.peer.x.XGraphicsEnvironment"); + } + + public GraphicsEnvironment getLocalGraphicsEnvironment() + { + return new XGraphicsEnvironment(); + } + + /** + * Returns the font peer for a font with the specified name and attributes. + * + * @param name the font name + * @param attrs the font attributes + * + * @return the font peer for a font with the specified name and attributes + */ + public ClasspathFontPeer getClasspathFontPeer(String name, Map attrs) + { + ClasspathFontPeer font; + if ("true".equals(System.getProperty("escherpeer.usexfonts"))) + { + String canonical = XFontPeer.encodeFont(name, attrs); + if (!fontCache.containsKey(canonical)) + { + font = new XFontPeer(name, attrs); + fontCache.put(canonical, font); + } + else + { + font = fontCache.get(canonical); + } + } + else + { + String canonical = OpenTypeFontPeer.encodeFont(name, attrs); + if (!fontCache.containsKey(canonical)) + { + font = new OpenTypeFontPeer(name, attrs); + fontCache.put(canonical, font); + } + else + { + font = fontCache.get(canonical); + } + } + return font; + } + + public Font createFont(int format, InputStream stream) + { + return null; + } + + public RobotPeer createRobot(GraphicsDevice screen) throws AWTException + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public EmbeddedWindowPeer createEmbeddedWindow(EmbeddedWindow w) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected ButtonPeer createButton(Button target) + { + checkHeadLess("No ButtonPeer can be created in an headless" + + "graphics environment."); + + return new SwingButtonPeer(target); + } + + protected TextFieldPeer createTextField(TextField target) + { + checkHeadLess("No TextFieldPeer can be created in an headless " + + "graphics environment."); + + return new SwingTextFieldPeer(target); + } + + protected LabelPeer createLabel(Label target) + { + checkHeadLess("No LabelPeer can be created in an headless graphics " + + "environment."); + return new SwingLabelPeer(target); + } + + protected ListPeer createList(List target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected CheckboxPeer createCheckbox(Checkbox target) + { + checkHeadLess("No CheckboxPeer can be created in an headless graphics " + + "environment."); + + return new SwingCheckboxPeer(target); + } + + protected ScrollbarPeer createScrollbar(Scrollbar target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected ScrollPanePeer createScrollPane(ScrollPane target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected TextAreaPeer createTextArea(TextArea target) + { + checkHeadLess("No TextAreaPeer can be created in an headless graphics " + + "environment."); + + return new SwingTextAreaPeer(target); + } + + protected ChoicePeer createChoice(Choice target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected FramePeer createFrame(Frame target) + { + XFramePeer frame = new XFramePeer(target); + return frame; + } + + protected CanvasPeer createCanvas(Canvas target) + { + return new SwingCanvasPeer(target); + } + + protected PanelPeer createPanel(Panel target) + { + return new SwingPanelPeer(target); + } + + protected WindowPeer createWindow(Window target) + { + return new XWindowPeer(target); + } + + protected DialogPeer createDialog(Dialog target) + { + return new XDialogPeer(target); + } + + protected MenuBarPeer createMenuBar(MenuBar target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected MenuPeer createMenu(Menu target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected PopupMenuPeer createPopupMenu(PopupMenu target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected MenuItemPeer createMenuItem(MenuItem target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected FileDialogPeer createFileDialog(FileDialog target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected CheckboxMenuItemPeer createCheckboxMenuItem(CheckboxMenuItem target) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + protected FontPeer getFontPeer(String name, int style) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Dimension getScreenSize() + { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gd.getDefaultConfiguration(); + XGraphicsConfiguration xgc = (XGraphicsConfiguration) gc; + + return xgc.getSize(); + } + + public int getScreenResolution() + { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gd.getDefaultConfiguration(); + XGraphicsConfiguration xgc = (XGraphicsConfiguration) gc; + + return xgc.getResolution(); + } + + /** + * Returns the color model used by this toolkit. + * + * @return the color model used by this toolkit + */ + public ColorModel getColorModel() + { + // TODO: I assume 24 bit depth here, we can do this better. + if (colorModel == null) + colorModel = new DirectColorModel(24, 0xFF0000, 0xFF00, 0xFF); + return colorModel; + } + + public String[] getFontList() + { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + return ge.getAvailableFontFamilyNames(); + } + + public FontMetrics getFontMetrics(Font name) + { + ClasspathFontPeer peer = (ClasspathFontPeer) name.getPeer(); + return peer.getFontMetrics(name); + } + + public void sync() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Returns an image that has its pixel data loaded from a file with the + * specified name. If that file doesn't exist, an empty or error image + * is returned instead. + * + * @param name the filename of the file that contains the pixel data + * + * @return the image + */ + public Image getImage(String name) + { + Image image; + try + { + File file = new File(name); + image = getImage(file.toURL()); + } + catch (MalformedURLException ex) + { + // TODO: Replace by a more meaningful error image instead. + image = null; + } + return image; + } + + /** + * Returns an image that has its pixel data loaded from the specified URL. + * If the image cannot be loaded for some reason, an empty or error image + * is returned instead. + * + * @param url the URL to the image data + * + * @return the image + */ + public Image getImage(URL url) + { + Image image; + if (imageCache.containsKey(url)) + { + image = (Image) imageCache.get(url); + } + else + { + image = createImage(url); + imageCache.put(url, image); + } + return image; + } + + /** + * Returns an image that has its pixel data loaded from a file with the + * specified name. If that file doesn't exist, an empty or error image + * is returned instead. + * + * @param filename the filename of the file that contains the pixel data + * + * @return the image + */ + public Image createImage(String filename) + { + Image im; + try + { + File file = new File(filename); + URL url = file.toURL(); + im = createImage(url); + } + catch (MalformedURLException ex) + { + im = createErrorImage(); + } + return im; + } + + /** + * Returns an image that has its pixel data loaded from the specified URL. + * If the image cannot be loaded for some reason, an empty or error image + * is returned instead. + * + * @param url the URL to the image data + * + * @return the image + */ + public Image createImage(URL url) + { + Image image; + try + { + image = createImage(url.openStream()); + } + catch (IOException ex) + { + image = createErrorImage(); + } + return image; + } + + /** + * Creates an image that is returned when calls to createImage() yields an + * error. + * + * @return an image that is returned when calls to createImage() yields an + * error + */ + private Image createErrorImage() + { + // TODO: Create better error image. + return new XImage(1, 1); + } + + public boolean prepareImage(Image image, int width, int height, ImageObserver observer) + { + Image scaled = AbstractGraphics2D.prepareImage(image, width, height); + return checkImage(image, width, height, observer) == ImageObserver.ALLBITS; + } + + public int checkImage(Image image, int width, int height, ImageObserver observer) + { + // Images are loaded synchronously, so we don't bother and return true. + return ImageObserver.ALLBITS; + } + + public Image createImage(ImageProducer producer) + { + ImageConverter conv = new ImageConverter(); + producer.startProduction(conv); + Image image = conv.getImage(); + return image; + } + + public Image createImage(byte[] data, int offset, int len) + { + Image image; + try + { + ByteArrayInputStream i = new ByteArrayInputStream(data, offset, len); + image = createImage(i); + } + catch (IOException ex) + { + image = createErrorImage(); + } + return image; + } + + private Image createImage(InputStream i) + throws IOException + { + Image image; + BufferedImage buffered = ImageIO.read(i); + // If the bufferedimage is opaque, then we can copy it over to an + // X Pixmap for faster drawing. + if (buffered != null && buffered.getTransparency() == Transparency.OPAQUE) + { + ImageProducer source = buffered.getSource(); + image = createImage(source); + } + else if (buffered != null) + { + image = buffered; + } + else + { + image = createErrorImage(); + } + return image; + } + + public PrintJob getPrintJob(Frame frame, String title, Properties props) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public void beep() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Clipboard getSystemClipboard() + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Returns the eventqueue used by the XLib peers. + * + * @return the eventqueue used by the XLib peers + */ + protected EventQueue getSystemEventQueueImpl() + { + if (eventQueue == null) + eventQueue = new EventQueue(); + return eventQueue; + } + + public DragSourceContextPeer createDragSourceContextPeer(DragGestureEvent e) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + public Map mapInputMethodHighlight(InputMethodHighlight highlight) + { + // TODO: Implement this. + throw new UnsupportedOperationException("Not yet implemented."); + } + + /** + * Helper method to quickly fetch the default device (X Display). + * + * @return the default XGraphicsDevice + */ + static XGraphicsDevice getDefaultDevice() + { + XGraphicsEnvironment env = (XGraphicsEnvironment) + XGraphicsEnvironment.getLocalGraphicsEnvironment(); + return (XGraphicsDevice) env.getDefaultScreenDevice(); + } + + @Override + public boolean isModalExclusionTypeSupported(ModalExclusionType modalExclusionType) + { + // TODO Auto-generated method stub + return false; + } + + @Override + public boolean isModalityTypeSupported(ModalityType modalityType) + { + // TODO Auto-generated method stub + return false; + } + + private void checkHeadLess(String message) throws HeadlessException + { + if(GraphicsEnvironment.isHeadless()) + { + if(message == null) + message = "This method cannot be called in headless mode."; + + throw new HeadlessException(message); + } + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/XWindowPeer.java b/libjava/classpath/gnu/java/awt/peer/x/XWindowPeer.java new file mode 100644 index 000000000..541eb74fa --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/XWindowPeer.java @@ -0,0 +1,303 @@ +/* XWindowPeer.java -- Window peer for X + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.peer.x; + +import java.awt.Component; +import java.awt.Dialog; +import java.awt.EventQueue; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Frame; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.GraphicsDevice; +import java.awt.GraphicsEnvironment; +import java.awt.Image; +import java.awt.Insets; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.PaintEvent; +import java.awt.event.WindowEvent; +import java.awt.image.VolatileImage; + +import gnu.x11.Atom; +import gnu.x11.Window; +import gnu.x11.event.Event; + +import gnu.java.awt.font.OpenTypeFontPeer; +import gnu.java.awt.peer.ClasspathFontPeer; +import gnu.java.awt.peer.swing.SwingWindowPeer; + +public class XWindowPeer + extends SwingWindowPeer +{ + + private static int standardSelect = Event.BUTTON_PRESS_MASK + | Event.BUTTON_RELEASE_MASK + | Event.POINTER_MOTION_MASK + // | Event.RESIZE_REDIRECT_MASK // + | Event.EXPOSURE_MASK + | Event.PROPERTY_CHANGE_MASK + //| Event.STRUCTURE_NOTIFY_MASK + //| Event.SUBSTRUCTURE_NOTIFY_MASK + | Event.KEY_PRESS_MASK + | Event.KEY_RELEASE_MASK + //| Event.VISIBILITY_CHANGE_MASK // + ; + + /** + * The X window. + */ + protected Window xwindow; + + /** + * The frame insets. These get updated in {@link #show()}. + */ + private Insets insets; + + XWindowPeer(java.awt.Window window) + { + super(window); + XGraphicsDevice dev = XToolkit.getDefaultDevice(); + + // TODO: Maybe initialize lazily in show(). + Window.Attributes atts = new Window.Attributes(); + // FIXME: Howto generate a Window without decorations? + int x = Math.max(window.getX(), 0); + int y = Math.max(window.getY(), 0); + int w = Math.max(window.getWidth(), 1); + int h = Math.max(window.getHeight(), 1); + xwindow = new Window(dev.getDisplay().default_root, x, y, w, h, 0, atts); + xwindow.select_input(standardSelect); + + dev.getEventPump().registerWindow(xwindow, window); + xwindow.set_wm_delete_window(); + + boolean undecorated; + if (awtComponent instanceof Frame) + { + Frame f = (Frame) awtComponent; + undecorated = f.isUndecorated(); + } + else if (awtComponent instanceof Dialog) + { + Dialog d = (Dialog) awtComponent; + undecorated = d.isUndecorated(); + } + else + { + undecorated = true; + } + if (undecorated) + { + // First try the Motif implementation of undecorated frames. This + // is semantically closest and supported by all major window + // managers. + // TODO: At the time of writing this, there's no freedesktop.org + // standard extension that matches the required semantic. Maybe + // undecorated frames are added in the future, if so, then use these. + Atom at = Atom.intern(dev.getDisplay(), "_MOTIF_WM_HINTS"); + if (at != null) + { + xwindow.change_property(Window.REPLACE, at, at, 32, + new int[]{1 << 1, 0, 0, 0, 0}, 0, 5); + } + } + insets = new Insets(0, 0, 0, 0); + } + + public void toBack() + { + // TODO Auto-generated method stub + + } + + public void toFront() + { + // TODO Auto-generated method stub + + } + + public void updateAlwaysOnTop() + { + // TODO Auto-generated method stub + + } + + public boolean requestWindowFocus() + { + // TODO Auto-generated method stub + return false; + } + + public Point getLocationOnScreen() + { + return new Point(xwindow.x, xwindow.y); + } + + /** + * Returns a XGraphics suitable for drawing on this frame. + * + * @return a XGraphics suitable for drawing on this frame + */ + public Graphics getGraphics() + { + XGraphics2D xg2d = new XGraphics2D(xwindow); + xg2d.setColor(awtComponent.getForeground()); + xg2d.setBackground(awtComponent.getBackground()); + xg2d.setFont(awtComponent.getFont()); + return xg2d; + } + + public Image createImage(int w, int h) + { + // FIXME: Should return a buffered image. + return createVolatileImage(w, h); + } + + @Override + public VolatileImage createVolatileImage(int width, int height) + { + GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); + GraphicsDevice gd = ge.getDefaultScreenDevice(); + GraphicsConfiguration gc = gd.getDefaultConfiguration(); + return gc.createCompatibleVolatileImage(width, height); + } + + /** + * Makes the component visible. This is called by {@link Component#show()}. + * + * This is implemented to call setVisible(true) on the Swing component. + */ + public void show() + { + // Prevent ResizeRedirect events. + //xwindow.select_input(Event.NO_EVENT_MASK); + //xwindow.select_input(noResizeRedirectSelect); + + XGraphicsDevice dev = XToolkit.getDefaultDevice(); + xwindow.map(); + EventQueue eq = XToolkit.getDefaultToolkit().getSystemEventQueue(); + java.awt.Window w = (java.awt.Window) super.awtComponent; + eq.postEvent(new WindowEvent(w, WindowEvent.WINDOW_OPENED)); + eq.postEvent(new PaintEvent(w, PaintEvent.PAINT, + new Rectangle(0, 0, w.getWidth(), + w.getHeight()))); + + Graphics g = getGraphics(); + g.clearRect(0, 0, awtComponent.getWidth(), awtComponent.getHeight()); + g.dispose(); +// // Reset input selection. +// atts.set_override_redirect(false); +// xwindow.change_attributes(atts); + + // Determine the frame insets. + Atom atom = (Atom) Atom.intern(dev.getDisplay(), "_NET_FRAME_EXTENTS"); + Window.Property p = xwindow.get_property(false, atom, Atom.CARDINAL, 0, + Window.MAX_WM_LENGTH); + if (p.format() != 0) + { + insets = new Insets(p.value(0), p.value(1), p.value(2), p.value(3)); + Window.Changes ch = new Window.Changes(); + ch.width(awtComponent.getWidth() - insets.left - insets.top); + ch.height(awtComponent.getHeight() - insets.top - insets.bottom); + xwindow.configure(ch); + } + + } + + /** + * Makes the component invisible. This is called from + * {@link Component#hide()}. + * + * This is implemented to call setVisible(false) on the Swing component. + */ + public void hide() + { + xwindow.unmap(); + } + + /** + * Notifies the peer that the bounds of this component have changed. This + * is called by {@link Component#reshape(int, int, int, int)}. + * + * This is implemented to call setBounds() on the Swing component. + * + * @param x the X coordinate of the upper left corner of the component + * @param y the Y coordinate of the upper left corner of the component + * @param width the width of the component + * @param height the height of the component + */ + public void reshape(int x, int y, int width, int height) + { + Insets i = insets; + xwindow.move_resize(x - i.left, y - i.right, width - i.left - i.right, + height - i.top - i.bottom); + } + + public Insets insets() + { + return (Insets) insets.clone(); + } + + /** + * Returns the font metrics for the specified font. + * + * @return the font metrics for the specified font + */ + public FontMetrics getFontMetrics(Font font) + { + ClasspathFontPeer fontPeer = (ClasspathFontPeer) font.getPeer(); + return fontPeer.getFontMetrics(font); + } + + /** + * Unregisters the window in the event pump when it is closed. + */ + protected void finalize() + { + XGraphicsDevice dev = XToolkit.getDefaultDevice(); + dev.getEventPump().unregisterWindow(xwindow); + } + + public Window getXwindow() + { + return xwindow; + } +} diff --git a/libjava/classpath/gnu/java/awt/peer/x/ZPixmapDataBuffer.java b/libjava/classpath/gnu/java/awt/peer/x/ZPixmapDataBuffer.java new file mode 100644 index 000000000..cf40f4d69 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/peer/x/ZPixmapDataBuffer.java @@ -0,0 +1,67 @@ +package gnu.java.awt.peer.x; + +import gnu.x11.Display; +import gnu.x11.image.ZPixmap; + +import java.awt.GraphicsEnvironment; +import java.awt.image.DataBuffer; + +/** + * A DataBuffer implementation that is based on a ZPixmap. This is used + * as backing store for BufferedImages. + */ +class ZPixmapDataBuffer + extends DataBuffer +{ + + /** + * The backing ZPixmap. + */ + private ZPixmap zpixmap; + + /** + * Creates a new ZPixmapDataBuffer with a specified width and height. + * + * @param d the X display + * @param w the width + * @param h the height + */ + ZPixmapDataBuffer(int w, int h) + { + super(TYPE_BYTE, w * h * 3); // TODO: Support non-24-bit-resolutions. + GraphicsEnvironment env = + GraphicsEnvironment.getLocalGraphicsEnvironment(); + XGraphicsDevice dev = (XGraphicsDevice) env.getDefaultScreenDevice(); + Display d = dev.getDisplay(); + zpixmap = new ZPixmap(d, w, h, d.default_pixmap_format); + } + + /** + * Creates a ZPixmapDataBuffer from an existing ZPixmap. + * + * @param zpixmap the ZPixmap to wrap + */ + ZPixmapDataBuffer(ZPixmap zpixmap) + { + super(TYPE_BYTE, zpixmap.get_data_length()); + this.zpixmap = zpixmap; + } + + @Override + public int getElem(int bank, int i) + { + return 0xff & zpixmap.get_data_element(i); + } + + @Override + public void setElem(int bank, int i, int val) + { + zpixmap.set_data_element(i, (byte) val); + } + + ZPixmap getZPixmap() + { + return zpixmap; + } + +} diff --git a/libjava/classpath/gnu/java/awt/print/JavaPrinterGraphics.java b/libjava/classpath/gnu/java/awt/print/JavaPrinterGraphics.java new file mode 100644 index 000000000..64d197cd0 --- /dev/null +++ b/libjava/classpath/gnu/java/awt/print/JavaPrinterGraphics.java @@ -0,0 +1,518 @@ +/* JavaPrinterGraphics.java -- AWT printer rendering class. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.print; + +import gnu.java.awt.peer.gtk.CairoSurface; + +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics; +import java.awt.Image; +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.image.ImageObserver; +import java.awt.image.PixelGrabber; +import java.awt.print.PageFormat; +import java.awt.print.Pageable; +import java.awt.print.Paper; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterGraphics; +import java.awt.print.PrinterJob; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.text.AttributedCharacterIterator; + +/** + * Graphics context to draw to PostScript. + * + * @author Sven de Marothy + */ +public class JavaPrinterGraphics extends Graphics implements PrinterGraphics +{ + + /** + * The used graphics context. + */ + private Graphics g; + + /** + * The associated printer job. + */ + private PrinterJob printerJob; + + /** + * Rendering resolution + */ + private static final double DPI = 72.0; + + /** + * Rendered image size. + */ + private int xSize, ySize; + + /** + * The image to render to. + */ + private Image image; + + public JavaPrinterGraphics( PrinterJob printerJob ) + { + this.printerJob = printerJob; + } + + /** + * Spool a document to PostScript. + * If Pageable is non-null, it will print that, otherwise it will use + * the supplied printable and pageFormat. + */ + public SpooledDocument spoolPostScript(Printable printable, + PageFormat pageFormat, + Pageable pageable) + throws PrinterException + { + try + { + // spool to a temporary file + File temp = File.createTempFile("cpspool", ".ps"); + temp.deleteOnExit(); + + PrintWriter out = new PrintWriter + (new BufferedWriter + (new OutputStreamWriter + (new FileOutputStream(temp), "ISO8859_1"), 1000000)); + + writePSHeader(out); + + if(pageable != null) + { + for(int index = 0; index < pageable.getNumberOfPages(); index++) + spoolPage(out, pageable.getPrintable(index), + pageable.getPageFormat(index), index); + } + else + { + int index = 0; + while(spoolPage(out, printable, pageFormat, index++) == + Printable.PAGE_EXISTS) + ; + } + out.println("%%Trailer"); + out.println("%%EOF"); + out.close(); + return new SpooledDocument( temp ); + } + catch (IOException e) + { + PrinterException pe = new PrinterException(); + pe.initCause(e); + throw pe; + } + } + + /** + * Spools a single page, returns NO_SUCH_PAGE unsuccessful, + * PAGE_EXISTS if it was. + */ + public int spoolPage(PrintWriter out, + Printable printable, + PageFormat pageFormat, + int index) throws IOException, PrinterException + { + initImage( pageFormat ); + if(printable.print(this, pageFormat, index) == Printable.NO_SUCH_PAGE) + return Printable.NO_SUCH_PAGE; + g.dispose(); + g = null; + writePage( out, pageFormat ); + return Printable.PAGE_EXISTS; + } + + private void initImage(PageFormat pageFormat) + { + // Create a really big image and draw to that. + xSize = (int)(DPI*pageFormat.getWidth()/72.0); + ySize = (int)(DPI*pageFormat.getHeight()/72.0); + + // Swap X and Y sizes if it's a Landscape page. + if( pageFormat.getOrientation() != PageFormat.PORTRAIT ) + { + int t = xSize; + xSize = ySize; + ySize = t; + } + + // FIXME: This should at least be BufferedImage. + // Fix once we have a working B.I. + // Graphics2D should also be supported of course. + image = CairoSurface.getBufferedImage(xSize, ySize); + + g = image.getGraphics(); + setColor(Color.white); + fillRect(0, 0, xSize, ySize); + setColor(Color.black); + } + + private void writePSHeader(PrintWriter out) + { + out.println("%!PS-Adobe-3.0"); + out.println("%%Title: "+printerJob.getJobName()); + out.println("%%Creator: GNU Classpath "); + out.println("%%DocumentData: Clean8Bit"); + + out.println("%%DocumentNeededResources: font Times-Roman Helvetica Courier"); + // out.println("%%Pages: "+); // FIXME # pages. + out.println("%%EndComments"); + + out.println("%%BeginProlog"); + out.println("%%EndProlog"); + out.println("%%BeginSetup"); + + // FIXME: Paper name + // E.g. "A4" "Letter" + // out.println("%%BeginFeature: *PageSize A4"); + + out.println("%%EndFeature"); + + out.println("%%EndSetup"); + + // out.println("%%Page: 1 1"); + } + + private void writePage(PrintWriter out, PageFormat pageFormat) + { + out.println("%%BeginPageSetup"); + + Paper p = pageFormat.getPaper(); + double pWidth = p.getWidth(); + double pHeight = p.getHeight(); + + if( pageFormat.getOrientation() == PageFormat.PORTRAIT ) + out.println( "%%Orientation: Portrait" ); + else + { + out.println( "%%Orientation: Landscape" ); + double t = pWidth; + pWidth = pHeight; + pHeight = t; + } + + out.println("gsave % first save"); + + // 595x842; 612x792 respectively + out.println("<< /PageSize [" +pWidth + " "+pHeight+ "] >> setpagedevice"); + + // invert the Y axis so that we get screen-like coordinates instead. + AffineTransform pageTransform = new AffineTransform(); + if( pageFormat.getOrientation() == PageFormat.REVERSE_LANDSCAPE ) + { + pageTransform.translate(pWidth, pHeight); + pageTransform.scale(-1.0, -1.0); + } + concatCTM(out, pageTransform); + out.println("%%EndPageSetup"); + + out.println("gsave"); + + + // Draw the image + out.println(xSize+" "+ySize+" 8 [1 0 0 -1 0 "+ySize+" ]"); + out.println("{currentfile 3 string readhexstring pop} bind"); + out.println("false 3 colorimage"); + int[] pixels = new int[xSize * ySize]; + PixelGrabber pg = new PixelGrabber(image, 0, 0, xSize, ySize, pixels, 0, xSize); + + try { + pg.grabPixels(); + } catch (InterruptedException e) { + out.println("% Bug getting pixels!"); + } + + int n = 0; + for (int j = 0; j < ySize; j++) { + for (int i = 0; i < xSize; i++) { + out.print( colorTripleHex(pixels[j * xSize + i]) ); + if(((++n)%11) == 0) out.println(); + } + } + + out.println(); + out.println("%%EOF"); + out.println("grestore"); + out.println("showpage"); + } + + /** + * Get a nonsperated hex RGB triple, e.g. FFFFFF = white + */ + private String colorTripleHex(int num){ + String s = ""; + + try { + s = Integer.toHexString( ( num & 0x00FFFFFF ) ); + if( s.length() < 6 ) + { + s = "000000"+s; + return s.substring(s.length()-6); + } + } catch (Exception e){ + s = "FFFFFF"; + } + + return s; + } + + private void concatCTM(PrintWriter out, AffineTransform Tx){ + double[] matrixElements = new double[6]; + Tx.getMatrix(matrixElements); + + out.print("[ "); + for(int i=0;i<6;i++) + out.print(matrixElements[i]+" "); + out.println("] concat"); + } + + //----------------------------------------------------------------------------- + /** + * PrinterGraphics method - Returns the printer job associated with this object. + */ + public PrinterJob getPrinterJob() + { + return printerJob; + } + + /** + * The rest of the methods here are just pass-throughs to g. + */ + public void clearRect(int x, int y, int width, int height) + { + g.clearRect(x, y, width, height); + } + + public void clipRect(int x, int y, int width, int height) + { + g.clipRect(x, y, width, height); + } + + public void copyArea(int x, int y, int width, int height, int dx, int dy) + { + g.copyArea(x, y, width, height, dx, dy); + } + + public Graphics create() + { + return g.create(); + } + + public void dispose() + { + } + + public void drawArc(int x, int y, int width, int height, int startAngle, + int arcAngle) + { + g.drawArc(x, y, width, height, startAngle, arcAngle); + } + + public boolean drawImage(Image img, int x, int y, Color bgcolor, + ImageObserver observer) + { + return g.drawImage(img, x, y, bgcolor, observer); + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + return g.drawImage(img, x, y, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + return g.drawImage(img, x, y, width, height, bgcolor, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) + { + return g.drawImage(img, x, y, width, height, observer); + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, Color bgcolor, + ImageObserver observer) + { + return g.drawImage(img, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, bgcolor, observer); + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, ImageObserver observer) + { + return g.drawImage(img, dx1, dy1, dx2, dy2, + sx1, sy1, sx2, sy2, observer); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + g.drawLine(x1, y1, x2, y2); + } + + public void drawOval(int x, int y, int width, int height) + { + g.drawOval(x, y, width, height); + } + + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + g.drawPolygon(xPoints, yPoints, nPoints); + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) + { + g.drawPolyline(xPoints, yPoints, nPoints); + } + + public void drawRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) + { + g.drawRoundRect(x, y, width, height, arcWidth, arcHeight); + } + + public void drawString(AttributedCharacterIterator iterator, int x, int y) + { + g.drawString(iterator, x, y); + } + + public void drawString(String str, int x, int y) + { + g.drawString(str, x, y); + } + + public void fillArc(int x, int y, int width, int height, + int startAngle, int arcAngle) + { + g.fillArc(x, y, width, height, startAngle, arcAngle); + } + + public void fillOval(int x, int y, int width, int height) + { + g.fillOval(x, y, width, height); + } + + public void fillPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + g.fillPolygon(xPoints, yPoints, nPoints); + } + + public void fillRect(int x, int y, int width, int height) + { + g.fillRect(x, y, width, height); + } + + public void fillRoundRect(int x, int y, int width, int height, + int arcWidth, int arcHeight) + { + g.fillRoundRect(x, y, width, height, arcWidth, arcHeight); + } + + public Shape getClip() + { + return g.getClip(); + } + + public Rectangle getClipBounds() + { + return g.getClipBounds(); + } + + public Color getColor() + { + return g.getColor(); + } + + public Font getFont() + { + return g.getFont(); + } + + public FontMetrics getFontMetrics(Font f) + { + return g.getFontMetrics(f); + } + + public void setClip(int x, int y, int width, int height) + { + g.setClip(x, y, width, height); + } + + public void setClip(Shape clip) + { + g.setClip(clip); + } + + public void setColor(Color c) + { + g.setColor(c); + } + + public void setFont(Font font) + { + g.setFont(font); + } + + public void setPaintMode() + { + g.setPaintMode(); + } + + public void setXORMode(Color c1) + { + g.setXORMode(c1); + } + + public void translate(int x, int y) + { + g.translate(x, y); + } +} diff --git a/libjava/classpath/gnu/java/awt/print/JavaPrinterJob.java b/libjava/classpath/gnu/java/awt/print/JavaPrinterJob.java new file mode 100644 index 000000000..295d231cb --- /dev/null +++ b/libjava/classpath/gnu/java/awt/print/JavaPrinterJob.java @@ -0,0 +1,403 @@ +/* JavaPrinterJob.java -- AWT printing implemented on javax.print. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.awt.print; + +import java.awt.HeadlessException; +import java.awt.print.PageFormat; +import java.awt.print.Pageable; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.util.Locale; + +import javax.print.CancelablePrintJob; +import javax.print.DocFlavor; +import javax.print.DocPrintJob; +import javax.print.PrintException; +import javax.print.PrintService; +import javax.print.PrintServiceLookup; +import javax.print.ServiceUI; +import javax.print.attribute.HashPrintRequestAttributeSet; +import javax.print.attribute.IntegerSyntax; +import javax.print.attribute.PrintRequestAttributeSet; +import javax.print.attribute.TextSyntax; +import javax.print.attribute.standard.Copies; +import javax.print.attribute.standard.JobName; +import javax.print.attribute.standard.OrientationRequested; +import javax.print.attribute.standard.RequestingUserName; + +/** + * This is the default implementation of PrinterJob + * + * @author Sven de Marothy + */ +public class JavaPrinterJob extends PrinterJob +{ + /** + * The print service associated with this job + */ + private PrintService printer = null; + + /** + * Printing options; + */ + private PrintRequestAttributeSet attributes; + + /** + * Available print services + */ + private static PrintService[] services; + + /** + * The actual print job. + */ + private DocPrintJob printJob; + + /** + * The Printable object to print. + */ + private Printable printable; + + /** + * Page format. + */ + private PageFormat pageFormat; + + /** + * A pageable, or null + */ + private Pageable pageable = null; + + /** + * Cancelled or not + */ + private boolean cancelled = false; + + static + { + // lookup all services without any constraints + services = PrintServiceLookup.lookupPrintServices + (DocFlavor.INPUT_STREAM.POSTSCRIPT, null); + } + + private static final Class copyClass = (new Copies(1)).getClass(); + private static final Class jobNameClass = (new JobName("", null)).getClass(); + private static final Class userNameClass = (new RequestingUserName("", null)).getClass(); + + /** + * Initializes a new instance of PrinterJob. + */ + public JavaPrinterJob() + { + attributes = new HashPrintRequestAttributeSet(); + setCopies(1); + setJobName("Java Printing"); + pageFormat = new PageFormat(); // default page format. + } + + private void getPageAttributes() + { + OrientationRequested orientation = (OrientationRequested) + attributes.get( OrientationRequested.LANDSCAPE.getCategory() ); + if( orientation == null) + return; + + if( orientation.equals(OrientationRequested.PORTRAIT) ) + pageFormat.setOrientation(PageFormat.PORTRAIT); + else if( orientation.equals(OrientationRequested.LANDSCAPE) ) + pageFormat.setOrientation(PageFormat.LANDSCAPE); + else if( orientation.equals(OrientationRequested.REVERSE_LANDSCAPE) ) + pageFormat.setOrientation(PageFormat.REVERSE_LANDSCAPE); + } + + /** + * Returns the number of copies to be printed. + * + * @return The number of copies to be printed. + */ + public int getCopies() + { + return ((IntegerSyntax)attributes.get( jobNameClass )).getValue(); + } + + /** + * Sets the number of copies to be printed. + * + * @param copies The number of copies to be printed. + */ + public void setCopies(int copies) + { + attributes.add( new Copies( copies ) ); + } + + /** + * Returns the name of the print job. + * + * @return The name of the print job. + */ + public String getJobName() + { + return ((TextSyntax)attributes.get( jobNameClass )).getValue(); + } + + /** + * Sets the name of the print job. + * + * @param job_name The name of the print job. + */ + public void setJobName(String job_name) + { + attributes.add( new JobName(job_name, Locale.getDefault()) ); + } + + /** + * Returns the printing user name. + * + * @return The printing username. + */ + public String getUserName() + { + return ((TextSyntax)attributes.get( userNameClass )).getValue(); + } + + /** + * Cancels an in progress print job. + */ + public void cancel() + { + try + { + if(printJob != null && (printJob instanceof CancelablePrintJob)) + { + ((CancelablePrintJob)printJob).cancel(); + cancelled = true; + } + } + catch(PrintException pe) + { + } + } + + /** + * Tests whether or not this job has been cancelled. + * + * @return true if this job has been cancelled, false + * otherwise. + */ + public boolean isCancelled() + { + return cancelled; + } + + /** + * Clones the specified PageFormat object then alters the + * clone so that it represents the default page format. + * + * @param page_format The PageFormat to clone. + * + * @return A new default page format. + */ + public PageFormat defaultPage(PageFormat page_format) + { + return new PageFormat(); + } + + /** + * Displays a dialog box to the user which allows the page format + * attributes to be modified. + * + * @param page_format The PageFormat object to modify. + * + * @return The modified PageFormat. + */ + public PageFormat pageDialog(PageFormat page_format) + throws HeadlessException + { + return defaultPage(null); + } + + /** + * Prints the pages. + */ + public void print() throws PrinterException + { + if( printable == null && pageable == null ) // nothing to print? + return; + + PostScriptGraphics2D pg = new PostScriptGraphics2D( this ); + SpooledDocument doc = pg.spoolPostScript( printable, pageFormat, + pageable ); + + cancelled = false; + printJob = printer.createPrintJob(); + try + { + printJob.print(doc, attributes); + } + catch (PrintException pe) + { + PrinterException p = new PrinterException(); + p.initCause(pe); + throw p; + } + // no printjob active. + printJob = null; + } + + /** + * Prints the page with given attributes. + */ + public void print (PrintRequestAttributeSet attributes) + throws PrinterException + { + this.attributes = attributes; + print(); + } + + /** + * Displays a dialog box to the user which allows the print job + * attributes to be modified. + * + * @return false if the user cancels the dialog box, + * true otherwise. + */ + public boolean printDialog() throws HeadlessException + { + return printDialog( attributes ); + } + + /** + * Displays a dialog box to the user which allows the print job + * attributes to be modified. + * + * @return false if the user cancels the dialog box, + * true otherwise. + */ + public boolean printDialog(PrintRequestAttributeSet attributes) + throws HeadlessException + { + PrintService chosenPrinter = ServiceUI.printDialog + (null, 50, 50, services, null, + DocFlavor.INPUT_STREAM.POSTSCRIPT, attributes); + + getPageAttributes(); + + if( chosenPrinter != null ) + { + try + { + setPrintService( chosenPrinter ); + } + catch(PrinterException pe) + { + // Should not happen. + } + return true; + } + return false; + } + + /** + * This sets the pages that are to be printed. + * + * @param pageable The pages to be printed, which may not be null. + */ + public void setPageable(Pageable pageable) + { + if( pageable == null ) + throw new NullPointerException("Pageable cannot be null."); + this.pageable = pageable; + } + + /** + * Sets this specified Printable as the one to use for + * rendering the pages on the print device. + * + * @param printable The Printable for the print job. + */ + public void setPrintable(Printable printable) + { + this.printable = printable; + } + + /** + * Sets the Printable and the page format for the pages + * to be printed. + * + * @param printable The Printable for the print job. + * @param page_format The PageFormat for the print job. + */ + public void setPrintable(Printable printable, PageFormat page_format) + { + this.printable = printable; + this.pageFormat = page_format; + } + + /** + * Makes any alterations to the specified PageFormat + * necessary to make it work with the current printer. The alterations + * are made to a clone of the input object, which is then returned. + * + * @param page_format The PageFormat to validate. + * + * @return The validated PageFormat. + */ + public PageFormat validatePage(PageFormat page_format) + { + // FIXME + return page_format; + } + + /** + * Change the printer for this print job to service. Subclasses that + * support setting the print service override this method. Throws + * PrinterException when the class doesn't support setting the printer, + * the service doesn't support Pageable or Printable interfaces for 2D + * print output. + * @param service The new printer to use. + * @throws PrinterException if service is not valid. + */ + public void setPrintService(PrintService service) + throws PrinterException + { + if(!service.isDocFlavorSupported(DocFlavor.INPUT_STREAM.POSTSCRIPT)) + throw new PrinterException("This printer service is not supported."); + printer = service; + } +} diff --git a/libjava/classpath/gnu/java/awt/print/PostScriptGraphics2D.java b/libjava/classpath/gnu/java/awt/print/PostScriptGraphics2D.java new file mode 100644 index 000000000..10fc25c2f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/print/PostScriptGraphics2D.java @@ -0,0 +1,1349 @@ +/* PostScriptGraphics2D.java -- AWT printer rendering class. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.print; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Composite; +import java.awt.Paint; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.GradientPaint; +import java.awt.Graphics; +import java.awt.GraphicsConfiguration; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Polygon; +import java.awt.Rectangle; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.geom.AffineTransform; +import java.awt.geom.Arc2D; +import java.awt.geom.Ellipse2D; +import java.awt.geom.RoundRectangle2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphVector; +import java.awt.font.TextLayout; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.renderable.RenderableImage; +import java.awt.image.RenderedImage; +import java.awt.image.ImageObserver; +import java.awt.image.PixelGrabber; +import java.awt.print.PageFormat; +import java.awt.print.Pageable; +import java.awt.print.Paper; +import java.awt.print.Printable; +import java.awt.print.PrinterException; +import java.awt.print.PrinterJob; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.text.AttributedCharacterIterator; +import java.util.Map; + +/** + * Class PostScriptGraphics2D - Class that implements the Graphics2D object, + * writing the output to a PostScript or EPS file + * + * @author Sven de Marothy + * + */ +class PostScriptGraphics2D extends Graphics2D +{ + /** + * The associated printer job. + */ + private PrinterJob printerJob; + + /** + * Output file. + */ + private PrintWriter out; + + // Graphics data + private AffineTransform currentTransform = new AffineTransform(); + private AffineTransform pageTransform; + private RenderingHints renderingHints; + private Paint currentPaint = null; + private Shape clipShape = null; + private Font currentFont = null; + private Color currentColor = Color.black; + private Color backgroundColor = Color.white; + private Stroke currentStroke = null; + private static Stroke ordinaryStroke = new BasicStroke(0.0f, + BasicStroke.CAP_BUTT, + BasicStroke.JOIN_MITER); + private float cx; // current drawing position + private float cy; // current drawing position + private boolean currentFontIsPS; // set if currentFont is one of the above + + // settings + private double pageX = 595; + private double pageY = 842; + private double Y = pageY; + private boolean gradientOn = false; + + /** + * Constructor + * + */ + public PostScriptGraphics2D( PrinterJob pg ) + { + printerJob = pg; + // create transform objects + pageTransform = new AffineTransform(); + currentTransform = new AffineTransform(); + + /* + Create Rendering hints + No text aliasing + Quality color and rendering + Bicubic interpolation + Fractional metrics supported + */ + renderingHints = new RenderingHints(null); + renderingHints.put(RenderingHints.KEY_RENDERING, + RenderingHints.VALUE_RENDER_QUALITY); + renderingHints.put(RenderingHints.KEY_TEXT_ANTIALIASING, + RenderingHints.VALUE_TEXT_ANTIALIAS_OFF); + renderingHints.put(RenderingHints.KEY_INTERPOLATION, + RenderingHints.VALUE_INTERPOLATION_BICUBIC); + renderingHints.put(RenderingHints.KEY_FRACTIONALMETRICS, + RenderingHints.VALUE_FRACTIONALMETRICS_ON); + renderingHints.put(RenderingHints.KEY_COLOR_RENDERING, + RenderingHints.VALUE_COLOR_RENDER_QUALITY); + } + + /** + * Spool a document to PostScript. + * If Pageable is non-null, it will print that, otherwise it will use + * the supplied printable and pageFormat. + */ + public SpooledDocument spoolPostScript(Printable printable, + PageFormat pageFormat, + Pageable pageable) + throws PrinterException + { + try + { + // spool to a temporary file + File temp = File.createTempFile("cpspool", ".ps"); + temp.deleteOnExit(); + + out = new PrintWriter(new BufferedWriter + (new OutputStreamWriter + (new FileOutputStream(temp), + "ISO8859_1"), 1000000)); + + writePSHeader(); + + if(pageable != null) + { + for(int index = 0; index < pageable.getNumberOfPages(); index++) + spoolPage(out, pageable.getPrintable(index), + pageable.getPageFormat(index), index); + } + else + { + int index = 0; + while(spoolPage(out, printable, pageFormat, index++) == + Printable.PAGE_EXISTS) + ; + } + out.println("%%Trailer"); + out.println("%%EOF"); + out.close(); + return new SpooledDocument( temp ); + } + catch (IOException e) + { + PrinterException pe = new PrinterException(); + pe.initCause(e); + throw pe; + } + } + + //-------------------------------------------------------------------------- + + /** + * Write the postscript file header, + * setup the page format and transforms. + */ + private void writePSHeader() + { + out.println("%!PS-Adobe-3.0"); + out.println("%%Title: "+printerJob.getJobName()); + out.println("%%Creator: GNU Classpath "); + out.println("%%DocumentData: Clean8Bit"); + + out.println("%%DocumentNeededResources: font Times-Roman Helvetica Courier"); + out.println("%%EndComments"); + + out.println("%%BeginProlog"); + out.println("%%EndProlog"); + out.println("%%BeginSetup"); + + out.println("%%EndFeature"); + setupFonts(); + out.println("%%EndSetup"); + + // set default fonts and colors + setFont( new Font("Dialog", Font.PLAIN, 12) ); + currentColor = Color.white; + currentStroke = new BasicStroke(); + setPaint(currentColor); + setStroke(currentStroke); + } + + /** + * setupFonts - set up the font dictionaries for + * helvetica, times and courier + */ + private void setupFonts() + { + out.println("/helveticaISO"); + out.println("/Helvetica findfont dup length dict begin"); + out.println("{ 1 index /FID eq { pop pop } { def } ifelse } forall"); + out.println("/Encoding ISOLatin1Encoding def"); + out.println("currentdict end definefont pop"); + + out.println("/timesISO"); + out.println("/Times-Roman findfont dup length dict begin"); + out.println("{ 1 index /FID eq { pop pop } { def } ifelse } forall"); + out.println("/Encoding ISOLatin1Encoding def"); + out.println("currentdict end definefont pop"); + + out.println("/courierISO"); + out.println("/Courier findfont dup length dict begin"); + out.println("{ 1 index /FID eq { pop pop } { def } ifelse } forall"); + out.println("/Encoding ISOLatin1Encoding def"); + out.println("currentdict end definefont pop"); + } + + /** + * Spools a single page, returns NO_SUCH_PAGE unsuccessful, + * PAGE_EXISTS if it was. + */ + public int spoolPage(PrintWriter out, + Printable printable, + PageFormat pageFormat, + int index) throws IOException, PrinterException + { + out.println("%%BeginPageSetup"); + + Paper p = pageFormat.getPaper(); + pageX = p.getWidth(); + pageY = p.getHeight(); + + if( pageFormat.getOrientation() == PageFormat.PORTRAIT ) + out.println( "%%Orientation: Portrait" ); + else + { + out.println( "%%Orientation: Landscape" ); + double t = pageX; + pageX = pageY; + pageY = t; + } + + setClip(0, 0, (int)pageX, (int)pageY); + + out.println("gsave % first save"); + + // 595x842; 612x792 respectively + out.println("<< /PageSize [" +pageX + " "+pageY+ "] >> setpagedevice"); + + if( pageFormat.getOrientation() != PageFormat.LANDSCAPE ) + { + pageTransform.translate(pageX, 0); + pageTransform.scale(-1.0, 1.0); + } + + // save the original CTM + pushCTM(); + concatCTM(pageTransform); + setTransform(new AffineTransform()); + + out.println("%%EndPageSetup"); + + out.println("gsave"); + + if( printable.print(this, pageFormat, index) == Printable.NO_SUCH_PAGE ) + return Printable.NO_SUCH_PAGE; + + out.println("grestore"); + out.println("showpage"); + + return Printable.PAGE_EXISTS; + } + + /** push the Current Transformation Matrix onto the PS stack */ + private void pushCTM() + { + out.println("matrix currentmatrix % pushCTM()"); + } + + /** pop the Current Transformation Matrix from the PS stack */ + private void popCTM() + { + out.println("setmatrix % restore CTM"); + } + + /////////////////////////////////////////////////////////////////////////// + + public Graphics create() + { + return null; + } + + public void drawOval(int x, int y, int width, int height) + { + out.println("% drawOval()"); + setStroke(ordinaryStroke); + draw(new Ellipse2D.Double(x, y, width, height)); + setStroke(currentStroke); + } + + public void drawPolyline(int[] xPoints, int[] yPoints, int nPoints) + { + if (nPoints <= 0 || xPoints.length < nPoints || yPoints.length < nPoints) + return; + out.println("newpath % drawPolyLine()"); + out.println(xPoints[0] + " " + yPoints[0] + " moveto"); + for (int i = 1; i < nPoints; i++) + out.println(xPoints[i] + " " + yPoints[i] + " lineto"); + out.println("closepath"); + out.println("stroke"); + } + + public void drawRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) + { + out.println("% drawRoundRect()"); + RoundRectangle2D.Double rr = new RoundRectangle2D.Double(x, y, width, + height, arcWidth, + arcHeight); + setStroke(ordinaryStroke); + draw(rr); + setStroke(currentStroke); + } + + public void fillRoundRect(int x, int y, int width, int height, int arcWidth, + int arcHeight) + { + out.println("% fillRoundRect()"); + RoundRectangle2D.Double rr = new RoundRectangle2D.Double(x, y, width, + height, arcWidth, + arcHeight); + fill(rr); + } + + public void drawArc(int x, int y, int width, int height, int startAngle, + int arcAngle) + { + setStroke(ordinaryStroke); + draw(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.OPEN)); + setStroke(currentStroke); + } + + public void fillArc(int x, int y, int width, int height, int startAngle, + int arcAngle) + { + fill(new Arc2D.Double(x, y, width, height, startAngle, arcAngle, Arc2D.PIE)); + } + + public void fillOval(int x, int y, int width, int height) + { + out.println("% fillOval()"); + fill( new Ellipse2D.Double(x, y, width, height) ); + } + + public void fillPolygon(int[] x, int[] y, int nPoints) + { + out.println("% fillPolygon()"); + fill( new Polygon(x, y, nPoints) ); + } + + public void drawLine(int x1, int y1, int x2, int y2) + { + out.println("% drawLine()"); + setStroke(ordinaryStroke); + out.println("newpath"); + out.println(x1 + " " + (y1) + " moveto"); + out.println(x2 + " " + (y2) + " lineto"); + out.println("stroke"); + setStroke(currentStroke); + } + + //--------------- Image drawing ------------------------------------------ + public boolean drawImage(Image img, int x, int y, Color bgcolor, + ImageObserver observer) + { + int w = img.getWidth(null); + int h = img.getHeight(null); + + return drawImage(img, x, y, x + w, y + h, 0, 0, w - 1, h - 1, bgcolor, + observer); + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, Color bgcolor, + ImageObserver observer) + { + int n = 0; + boolean flipx = false; + boolean flipy = false; + + // swap X and Y's + if (sx1 > sx2) + { + n = sx1; + sx1 = sx2; + sx2 = n; + flipx = ! flipx; + } + if (sy1 > sy2) + { + n = sy1; + sy1 = sy2; + sy2 = n; + flipy = ! flipy; + } + if (dx1 > dx2) + { + n = dx1; + dx1 = dx2; + dx2 = n; + flipx = ! flipx; + } + if (dy1 > dy2) + { + n = dy1; + dy1 = dy2; + dy2 = n; + flipy = ! flipy; + } + n = 0; + int sw = sx2 - sx1; // source width + int sh = sy2 - sy1; // source height + int[] pixels = new int[sw * sh]; // pixel buffer + int dw = dx2 - dx1; // destination width + int dh = dy2 - dy1; // destination height + double x_scale = ((double) dw) / ((double) sw); + double y_scale = ((double) dh) / ((double) sh); + + out.println("% drawImage() 2"); + out.println("gsave"); + out.println(dx1 + " " + dy1 + " translate"); + out.println(dw + " " + dh + " scale"); + out.println(sw + " " + sh + " 8 [" + (flipx ? -sw : sw) + " 0 0 " + + (flipy ? -sh : sh) + " " + (flipx ? sw : 0) + " " + + (flipy ? sh : 0) + " ]"); + out.println("{currentfile 3 string readhexstring pop} bind"); + out.println("false 3 colorimage"); + + PixelGrabber pg = new PixelGrabber(img, sx1, sy1, sw, sh, pixels, 0, sw); + try + { + pg.grabPixels(); + } + catch (InterruptedException e) + { + System.err.println("interrupted waiting for pixels!"); + return (false); + } + + if ((pg.getStatus() & ImageObserver.ABORT) != 0) + { + System.err.println("image fetch aborted or errored"); + return (false); + } + + for (int j = 0; j < sh; j++) + { + for (int i = 0; i < sw; i++) + { + out.print(colorTripleHex(new Color(pixels[j * sw + i]))); + if (((++n) % 11) == 0) + out.println(); + } + } + + out.println(); + out.println("%%EOF"); + out.println("grestore"); + return true; + } + + public boolean drawImage(Image img, int dx1, int dy1, int dx2, int dy2, + int sx1, int sy1, int sx2, int sy2, + ImageObserver observer) + { + return drawImage(img, dx1, dy1, dx2, dy2, sx1, sy1, sx2, sy2, null, + observer); + } + + public boolean drawImage(Image img, int x, int y, ImageObserver observer) + { + return drawImage(img, x, y, null, observer); + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + Color bgcolor, ImageObserver observer) + { + int sw = img.getWidth(null); + int sh = img.getHeight(null); + return drawImage(img, x, y, x + width, y + height, /* destination */ + 0, 0, sw - 1, sh - 1, /* source */ + bgcolor, observer); + // correct? + } + + public boolean drawImage(Image img, int x, int y, int width, int height, + ImageObserver observer) + { + return drawImage(img, x, y, width, height, null, observer); + } + + /** Renders a BufferedImage that is filtered with a BufferedImageOp. */ + public void drawImage(BufferedImage img, BufferedImageOp op, int x, int y) + { + BufferedImage result = op.filter(img, null); + drawImage(result, x, y, null); + } + + /** Renders an image, applying a transform from image space + into user space before drawing. */ + public boolean drawImage(Image img, AffineTransform xform, ImageObserver obs) + { + AffineTransform oldTransform = new AffineTransform(currentTransform); + boolean ret; + + transform(xform); + ret = drawImage(img, 0, 0, null, obs); + setTransform(oldTransform); + + return ret; + } + + /** Renders a RenderableImage, applying a transform from image + space into user space before drawing. */ + public void drawRenderableImage(RenderableImage img, AffineTransform xform) + { + // FIXME + } + + /** Renders a RenderedImage, applying a transform from + image space into user space before drawing. */ + public void drawRenderedImage(RenderedImage img, AffineTransform xform) + { + // FIXME + } + + //------------------------------------------------------------------------- + public void drawPolygon(int[] xPoints, int[] yPoints, int nPoints) + { + setStroke(ordinaryStroke); + draw(new Polygon(xPoints, yPoints, nPoints)); + setStroke(currentStroke); + } + + public void drawString(String str, int x, int y) + { + drawString(str, (float) x, (float) y); + } + + public void drawString(String str, float x, float y) + { + if( str.trim().equals("") ) + return; // don't draw whitespace, silly! + + if( currentFontIsPS ) + { + drawStringPSFont(str, x, y); + return; + } + + TextLayout text = new TextLayout(str, currentFont, getFontRenderContext()); + Shape s = text.getOutline(AffineTransform.getTranslateInstance(x, y)); + drawStringShape(s); + } + + private void drawStringPSFont(String str, float x, float y) + { + out.println("% drawString PS font"); + out.println(x + " " + y + " moveto"); + saveAndInvertAxis(); + out.println("(" + str + ") show"); + restoreAxis(); + } + + private void saveAndInvertAxis() + { + // Invert the Y axis of the CTM. + popCTM(); + pushCTM(); + + double[] test = + { + pageTransform.getScaleX(), pageTransform.getShearY(), + pageTransform.getShearX(), pageTransform.getScaleY(), + pageTransform.getTranslateX(), + -pageTransform.getTranslateY() + pageY + }; + + double[] test2 = + { + currentTransform.getScaleX(), + currentTransform.getShearY(), + -currentTransform.getShearX(), + -currentTransform.getScaleY(), + currentTransform.getTranslateX(), + currentTransform.getTranslateY() + }; + + AffineTransform total = new AffineTransform(test); + total.concatenate(new AffineTransform(test2)); + concatCTM(total); + } + + private void restoreAxis() + { + // reset the CTM + popCTM(); + pushCTM(); + AffineTransform total = new AffineTransform(pageTransform); + total.concatenate(currentTransform); + concatCTM(total); + } + + /** + * special drawing routine for string shapes, + * which need to be drawn with the Y axis uninverted. + */ + private void drawStringShape(Shape s) + { + saveAndInvertAxis(); + + // draw the shape s with an inverted Y axis. + PathIterator pi = s.getPathIterator(null); + float[] coords = new float[6]; + + while (! pi.isDone()) + { + switch (pi.currentSegment(coords)) + { + case PathIterator.SEG_MOVETO: + out.println((coords[0]) + " " + (Y - coords[1]) + " moveto"); + cx = coords[0]; + cy = coords[1]; + break; + case PathIterator.SEG_LINETO: + out.println((coords[0]) + " " + (Y - coords[1]) + " lineto"); + cx = coords[0]; + cy = coords[1]; + break; + case PathIterator.SEG_QUADTO: + // convert to cubic bezier points + float x1 = (cx + 2 * coords[0]) / 3; + float y1 = (cy + 2 * coords[1]) / 3; + float x2 = (2 * coords[2] + coords[0]) / 3; + float y2 = (2 * coords[3] + coords[1]) / 3; + + out.print((x1) + " " + (Y - y1) + " "); + out.print((x2) + " " + (Y - y2) + " "); + out.println((coords[2]) + " " + (Y - coords[3]) + " curveto"); + cx = coords[2]; + cy = coords[3]; + break; + case PathIterator.SEG_CUBICTO: + out.print((coords[0]) + " " + (Y - coords[1]) + " "); + out.print((coords[2]) + " " + (Y - coords[3]) + " "); + out.println((coords[4]) + " " + (Y - coords[5]) + " curveto"); + cx = coords[4]; + cy = coords[5]; + break; + case PathIterator.SEG_CLOSE: + out.println("closepath"); + break; + } + pi.next(); + } + out.println("fill"); + + restoreAxis(); + } + + public void setColor(Color c) + { + /* don't set the color if it's already set */ + if (c.equals(currentColor)) + return; + gradientOn = false; + currentColor = c; + currentPaint = c; // Graphics2D extends colors to paint + + out.println(colorTriple(c) + " setrgbcolor"); + } + + public void clearRect(int x, int y, int width, int height) + { + out.println("% clearRect"); + Color c = currentColor; + setColor(backgroundColor); + fill(new Rectangle2D.Double(x, y, width, height)); + setColor(c); + } + + public void clipRect(int x, int y, int width, int height) + { + clip(new Rectangle2D.Double(x, y, width, height)); + } + + public void copyArea(int x, int y, int width, int height, int dx, int dy) + { + // FIXME + } + + public void fillRect(int x, int y, int width, int height) + { + fill(new Rectangle2D.Double(x, y, width, height)); + } + + public void dispose() + { + } + + public void setClip(int x, int y, int width, int height) + { + out.println("% setClip()"); + setClip(new Rectangle2D.Double(x, y, width, height)); + } + + public void setClip(Shape s) + { + clip(s); + } + + public Shape getClip() + { + return clipShape; + } + + public Rectangle getClipBounds() + { + return clipShape.getBounds(); + } + + public Color getColor() + { + return currentColor; + } + + public Font getFont() + { + return currentFont; + } + + public FontMetrics getFontMetrics() + { + return getFontMetrics(currentFont); + } + + public FontMetrics getFontMetrics(Font f) + { + // FIXME + return null; + } + + public void setFont(Font font) + { + out.println("% setfont()"); + if (font == null) + // use the default font + font = new Font("Dialog", Font.PLAIN, 12); + currentFont = font; + setPSFont(); // set up the PostScript fonts + } + + /** + * Setup the postscript font if the current font is one + */ + private void setPSFont() + { + currentFontIsPS = false; + + String s = currentFont.getName(); + out.println("% setPSFont: Fontname: " + s); + if (s.equalsIgnoreCase("Helvetica") || s.equalsIgnoreCase("SansSerif")) + out.print("/helveticaISO findfont "); + else if (s.equalsIgnoreCase("Times New Roman")) + out.print("/timesISO findfont "); + else if (s.equalsIgnoreCase("Courier")) + out.print("/courierISO findfont "); + else + return; + + currentFontIsPS = true; + + out.print(currentFont.getSize() + " scalefont "); + out.println("setfont"); + } + + /** XOR mode is not supported */ + public void setPaintMode() + { + } + + /** XOR mode is not supported */ + public void setXORMode(Color c1) + { + } + + public void close() + { + out.println("showpage"); + out.println("%%Trailer"); + out.println("grestore % restore original stuff"); + out.println("%%EOF"); + + try + { + out.close(); + } + catch (Exception e) + { + } + out = null; + } + + //---------------------------------------------------------------- + // Graphics2D stuff ---------------------------------------------- + + /** Sets the values of an arbitrary number of + preferences for the rendering algorithms. */ + public void addRenderingHints(Map hints) + { + /* rendering hint changes are disallowed */ + } + + /** write a shape to the file */ + private void writeShape(Shape s) + { + PathIterator pi = s.getPathIterator(null); + float[] coords = new float[6]; + + while (! pi.isDone()) + { + switch (pi.currentSegment(coords)) + { + case PathIterator.SEG_MOVETO: + out.println(coords[0] + " " + (coords[1]) + " moveto"); + cx = coords[0]; + cy = coords[1]; + break; + case PathIterator.SEG_LINETO: + out.println(coords[0] + " " + (coords[1]) + " lineto"); + cx = coords[0]; + cy = coords[1]; + break; + case PathIterator.SEG_QUADTO: + // convert to cubic bezier points + float x1 = (cx + 2 * coords[0]) / 3; + float y1 = (cy + 2 * coords[1]) / 3; + float x2 = (2 * coords[2] + coords[0]) / 3; + float y2 = (2 * coords[3] + coords[1]) / 3; + + out.print(x1 + " " + (Y - y1) + " "); + out.print(x2 + " " + (Y - y2) + " "); + out.println(coords[2] + " " + (Y - coords[3]) + " curveto"); + cx = coords[2]; + cy = coords[3]; + break; + case PathIterator.SEG_CUBICTO: + out.print(coords[0] + " " + coords[1] + " "); + out.print(coords[2] + " " + coords[3] + " "); + out.println(coords[4] + " " + coords[5] + " curveto"); + cx = coords[4]; + cy = coords[5]; + break; + case PathIterator.SEG_CLOSE: + out.println("closepath"); + break; + } + pi.next(); + } + } + + /** Intersects the current Clip with the interior of + the specified Shape and sets the Clip to the resulting intersection. */ + public void clip(Shape s) + { + clipShape = s; + out.println("% clip INACTIVE"); + // writeShape(s); + // out.println("clip"); + } + + /** Strokes the outline of a Shape using the + settings of the current Graphics2D context.*/ + public void draw(Shape s) + { + if(!(currentStroke instanceof BasicStroke)) + fill(currentStroke.createStrokedShape(s)); + + out.println("% draw"); + writeShape(s); + out.println("stroke"); + } + + /** Renders the text of the specified GlyphVector using the + Graphics2D context's rendering attributes. */ + public void drawGlyphVector(GlyphVector gv, float x, float y) + { + out.println("% drawGlyphVector"); + Shape s = gv.getOutline(); + drawStringShape(AffineTransform.getTranslateInstance(x, y) + .createTransformedShape(s)); + } + + /** Renders the text of the specified iterator, + using the Graphics2D context's current Paint.*/ + public void drawString(AttributedCharacterIterator iterator, float x, float y) + { + TextLayout text = new TextLayout(iterator, getFontRenderContext()); + Shape s = text.getOutline(AffineTransform.getTranslateInstance(x, y)); + drawStringShape(s); + } + + /** Renders the text of the specified iterator, + using the Graphics2D context's current Paint. */ + public void drawString(AttributedCharacterIterator iterator, int x, int y) + { + drawString(iterator, (float) x, (float) y); + } + + /** Fills the interior of a Shape using the settings of the Graphics2D context. */ + public void fill(Shape s) + { + out.println("% fill"); + if (! gradientOn) + { + writeShape(s); + out.println("fill"); + } + else + { + out.println("gsave"); + writeShape(s); + out.println("clip"); + writeGradient(); + out.println("shfill"); + out.println("grestore"); + } + } + + /** Returns the background color used for clearing a region. */ + public Color getBackground() + { + return backgroundColor; + } + + /** Returns the current Composite in the Graphics2D context. */ + public Composite getComposite() + { + // FIXME + return null; + } + + /** Returns the device configuration associated with this Graphics2D. */ + public GraphicsConfiguration getDeviceConfiguration() + { + // FIXME + out.println("% getDeviceConfiguration()"); + return null; + } + + /** Get the rendering context of the Font within this Graphics2D context. */ + public FontRenderContext getFontRenderContext() + { + out.println("% getFontRenderContext()"); + + double[] scaling = + { + pageTransform.getScaleX(), 0, 0, + -pageTransform.getScaleY(), 0, 0 + }; + + return (new FontRenderContext(new AffineTransform(scaling), false, true)); + } + + /** Returns the current Paint of the Graphics2D context. */ + public Paint getPaint() + { + return currentPaint; + } + + /** Returns the value of a single preference for the rendering algorithms. */ + public Object getRenderingHint(RenderingHints.Key hintKey) + { + return renderingHints.get(hintKey); + } + + /** Gets the preferences for the rendering algorithms. */ + public RenderingHints getRenderingHints() + { + return renderingHints; + } + + /** Returns the current Stroke in the Graphics2D context. */ + public Stroke getStroke() + { + return currentStroke; + } + + /** Returns a copy of the current Transform in the Graphics2D context. */ + public AffineTransform getTransform() + { + return currentTransform; + } + + /** + * Checks whether or not the specified Shape intersects + * the specified Rectangle, which is in device space. + */ + public boolean hit(Rectangle rect, Shape s, boolean onStroke) + { + Rectangle2D.Double r = new Rectangle2D.Double(rect.getX(), rect.getY(), + rect.getWidth(), + rect.getHeight()); + return s.intersects(r); + } + + /** Sets the background color for the Graphics2D context.*/ + public void setBackground(Color color) + { + out.println("% setBackground(" + color + ")"); + backgroundColor = color; + } + + /** Sets the Composite for the Graphics2D context. + Not supported. */ + public void setComposite(Composite comp) + { + } + + /** Sets the Paint attribute for the Graphics2D context.*/ + public void setPaint(Paint paint) + { + currentPaint = paint; + gradientOn = false; + if (paint instanceof Color) + { + setColor((Color) paint); + return; + } + if (paint instanceof GradientPaint) + { + gradientOn = true; + return; + } + } + + /* get a space seperated 0.0 - 1.0 color RGB triple */ + private String colorTriple(Color c) + { + return (((double) c.getRed() / 255.0) + " " + + ((double) c.getGreen() / 255.0) + " " + + ((double) c.getBlue() / 255.0)); + } + + /** + * Get a nonsperated hex RGB triple, eg FFFFFF = white + * used by writeGradient and drawImage + */ + private String colorTripleHex(Color c) + { + String r = "00" + Integer.toHexString(c.getRed()); + r = r.substring(r.length() - 2); + String g = "00" + Integer.toHexString(c.getGreen()); + g = g.substring(g.length() - 2); + String b = "00" + Integer.toHexString(c.getBlue()); + b = b.substring(b.length() - 2); + return r + g + b; + } + + /* write the current gradient fill */ + private void writeGradient() + { + GradientPaint paint = (GradientPaint) currentPaint; + out.println("% writeGradient()"); + + int n = 1; + double x; + double y; + double dx; + double dy; + Point2D p1 = currentTransform.transform(paint.getPoint1(), null); + Point2D p2 = currentTransform.transform(paint.getPoint2(), null); + x = p1.getX(); + y = p1.getY(); + dx = p2.getX() - x; + dy = p2.getY() - y; + + // get number of repetitions + while (x + n * dx < pageY && y + n * dy < pageX && x + n * dx > 0 + && y + n * dy > 0) + n++; + + out.println("<<"); // start + out.println("/ShadingType 2"); // gradient fill + out.println("/ColorSpace [ /DeviceRGB ]"); // RGB colors + out.print("/Coords ["); + out.print(x + " " + y + " " + (x + n * dx) + " " + (y + n * dy) + " "); + out.println("]"); // coordinates defining the axis + out.println("/Function <<"); + out.println("/FunctionType 0"); + out.println("/Order 1"); + out.println("/Domain [ 0 1 ]"); + out.println("/Range [ 0 1 0 1 0 1 ]"); + out.println("/BitsPerSample 8"); + out.println("/Size [ " + (1 + n) + " ]"); + out.print("/DataSource < " + colorTripleHex(paint.getColor1()) + " " + + colorTripleHex(paint.getColor2()) + " "); + for (; n > 1; n--) + if (paint.isCyclic()) + { + if ((n % 2) == 1) + out.print(colorTripleHex(paint.getColor1()) + " "); + else + out.print(colorTripleHex(paint.getColor2()) + " "); + } + else + out.print(colorTripleHex(paint.getColor2()) + " "); + out.println(">"); + out.println(">>"); + out.println(">>"); + } + + /** Sets the value of a single preference for the rendering algorithms. */ + public void setRenderingHint(RenderingHints.Key hintKey, Object hintValue) + { + /* we don't allow the changing of rendering hints. */ + } + + /** Replaces the values of all preferences for the rendering algorithms + with the specified hints. */ + public void setRenderingHints(Map hints) + { + /* we don't allow the changing of rendering hints. */ + } + + /** + * Sets the Stroke for the Graphics2D context. BasicStroke fully implemented. + */ + public void setStroke(Stroke s) + { + currentStroke = s; + + if (! (s instanceof BasicStroke)) + return; + + BasicStroke bs = (BasicStroke) s; + out.println("% setStroke()"); + try + { + // set the line width + out.println(bs.getLineWidth() + " setlinewidth"); + + // set the line dash + float[] dashArray = bs.getDashArray(); + if (dashArray != null) + { + out.print("[ "); + for (int i = 0; i < dashArray.length; i++) + out.print(dashArray[i] + " "); + out.println("] " + bs.getDashPhase() + " setdash"); + } + else + out.println("[] 0 setdash"); // set solid + + // set the line cap + switch (bs.getEndCap()) + { + case BasicStroke.CAP_BUTT: + out.println("0 setlinecap"); + break; + case BasicStroke.CAP_ROUND: + out.println("1 setlinecap"); + break; + case BasicStroke.CAP_SQUARE: + out.println("2 setlinecap"); + break; + } + + // set the line join + switch (bs.getLineJoin()) + { + case BasicStroke.JOIN_BEVEL: + out.println("2 setlinejoin"); + break; + case BasicStroke.JOIN_MITER: + out.println("0 setlinejoin"); + out.println(bs.getMiterLimit() + " setmiterlimit"); + break; + case BasicStroke.JOIN_ROUND: + out.println("1 setlinejoin"); + break; + } + } + catch (Exception e) + { + out.println("% Exception in setStroke()"); + } + } + + //////////////////// TRANSFORM SETTING ///////////////////////////////////// + private void concatCTM(AffineTransform Tx) + { + double[] matrixElements = new double[6]; + Tx.getMatrix(matrixElements); + + out.print("[ "); + for (int i = 0; i < 6; i++) + out.print(matrixElements[i] + " "); + out.println("] concat"); + } + + /** Sets the Transform in the Graphics2D context. */ + public void setTransform(AffineTransform Tx) + { + // set the transformation matrix; + currentTransform = Tx; + + // concatenate the current transform and the page transform + AffineTransform totalTransform = new AffineTransform(pageTransform); + totalTransform.concatenate(currentTransform); + out.println("% setTransform()"); + out.println("% pageTransform:" + pageTransform); + out.println("% currentTransform:" + currentTransform); + out.println("% totalTransform:" + totalTransform); + + popCTM(); + pushCTM(); // set the CTM to it's original state + concatCTM(totalTransform); // apply our transforms + } + + /** Composes an AffineTransform object with the Transform + in this Graphics2D according to the rule last-specified-first-applied. */ + public void transform(AffineTransform Tx) + { + // concatenate the current transform + currentTransform.concatenate(Tx); + // and the PS CTM + concatCTM(Tx); + } + + ////////////////////////// TRANSFORMS ////////////////////////////////////// + + /** shear transform */ + public void shear(double shx, double shy) + { + out.println("% shear()"); + AffineTransform Tx = new AffineTransform(); + Tx.shear(shx, shy); + transform(Tx); + } + + /** Translates the origin of the Graphics2D context + to the point (x, y) in the current coordinate system. */ + public void translate(int x, int y) + { + out.println("% translate()"); + AffineTransform Tx = new AffineTransform(); + Tx.translate(x, y); + transform(Tx); + } + + /** Translates the origin of the Graphics2D context + to the point (x, y) in the current coordinate system. */ + public void translate(double x, double y) + { + out.println("% translate(" + x + ", " + y + ")"); + AffineTransform Tx = new AffineTransform(); + Tx.translate(x, y); + transform(Tx); + } + + /** Concatenates the current Graphics2D Transform with a rotation transform.*/ + public void rotate(double theta) + { + out.println("% rotate(" + theta + ")"); + AffineTransform Tx = new AffineTransform(); + Tx.rotate(theta); + transform(Tx); + } + + /** Concatenates the current Graphics2D Transform with + a translated rotation transform.*/ + public void rotate(double theta, double x, double y) + { + out.println("% rotate()"); + AffineTransform Tx = new AffineTransform(); + Tx.rotate(theta, x, y); + transform(Tx); + } + + /** Concatenates the current Graphics2D Transform with a scaling + transformation Subsequent rendering is resized according to the + specified scaling factors relative to the previous scaling.*/ + public void scale(double sx, double sy) + { + out.println("% scale(" + sx + ", " + sy + ")"); + AffineTransform Tx = new AffineTransform(); + Tx.scale(sx, sy); + transform(Tx); + } +} diff --git a/libjava/classpath/gnu/java/awt/print/SpooledDocument.java b/libjava/classpath/gnu/java/awt/print/SpooledDocument.java new file mode 100644 index 000000000..54819984f --- /dev/null +++ b/libjava/classpath/gnu/java/awt/print/SpooledDocument.java @@ -0,0 +1,90 @@ +/* SpooledDocument.java -- Reurgitate a spooled PostScript file + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.awt.print; + +import javax.print.Doc; +import javax.print.DocFlavor; +import javax.print.attribute.DocAttributeSet; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.Reader; +import java.io.InputStream; +import java.io.InputStreamReader; + +public class SpooledDocument implements Doc +{ + private FileInputStream fis; + + public SpooledDocument(File file) + { + try + { + fis = new FileInputStream(file); + } + catch (FileNotFoundException ffne) + { + // Shouldn't happen. + } + } + + public DocAttributeSet getAttributes() + { + return null; + } + + public DocFlavor getDocFlavor() + { + return DocFlavor.INPUT_STREAM.POSTSCRIPT; + } + + public Object getPrintData() + { + return fis; + } + + public Reader getReaderForText() + { + return new InputStreamReader(fis); + } + + public InputStream getStreamForBytes() + { + return fis; + } +} diff --git a/libjava/classpath/gnu/java/beans/BeanInfoEmbryo.java b/libjava/classpath/gnu/java/beans/BeanInfoEmbryo.java new file mode 100644 index 000000000..cc474e817 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/BeanInfoEmbryo.java @@ -0,0 +1,171 @@ +/* gnu.java.beans.BeanInfoEmbryo + Copyright (C) 1998, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans; + +import java.beans.BeanDescriptor; +import java.beans.BeanInfo; +import java.beans.EventSetDescriptor; +import java.beans.IndexedPropertyDescriptor; +import java.beans.MethodDescriptor; +import java.beans.PropertyDescriptor; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; +import java.util.Map; +import java.util.TreeMap; +import java.util.Vector; + +/** + ** A BeanInfoEmbryo accumulates information about a Bean + ** while it is in the process of being created, and then + ** when you are done accumulating the information, the + ** getBeanInfo() method may be called to create a BeanInfo + ** object based on the information.

+ ** + ** This class is not well-synchronized. (It can be, it + ** just isn't yet.) + ** + ** @author John Keiser + ** @version 1.1.0, 30 Jul 1998 + ** @see java.beans.BeanInfo + **/ + +public class BeanInfoEmbryo { + + // by using a TreeMap the properties will be sorted alphabetically by name + // which matches the (undocumented) behavior of jdk + TreeMap properties = new TreeMap(); + Hashtable events = new Hashtable(); + Vector methods = new Vector(); + + BeanDescriptor beanDescriptor; + BeanInfo[] additionalBeanInfo; + java.awt.Image[] im; + String defaultPropertyName; + String defaultEventName; + + public BeanInfoEmbryo() { + } + + public BeanInfo getBeanInfo() { + int defaultProperty = -1; + int defaultEvent = -1; + + PropertyDescriptor[] Aproperties = new PropertyDescriptor[properties.size()]; + int i = 0; + Iterator it = properties.entrySet().iterator(); + while (it.hasNext()) { + Aproperties[i] = (PropertyDescriptor) (((Map.Entry)it.next()).getValue()); + if(defaultPropertyName != null && Aproperties[i].getName().equals(defaultPropertyName)) { + defaultProperty = i; + } + i++; + } + + EventSetDescriptor[] Aevents = new EventSetDescriptor[events.size()]; + i = 0; + Enumeration e = events.elements(); + while (e.hasMoreElements()) { + Aevents[i] = (EventSetDescriptor) e.nextElement(); + if(defaultEventName != null && Aevents[i].getName().equals(defaultEventName)) { + defaultEvent = i; + } + i++; + } + + MethodDescriptor[] Amethods = new MethodDescriptor[methods.size()]; + methods.copyInto(Amethods); + + return new ExplicitBeanInfo(beanDescriptor,additionalBeanInfo,Aproperties,defaultProperty,Aevents,defaultEvent,Amethods,im); + } + + public void setBeanDescriptor(BeanDescriptor b) { + beanDescriptor = b; + } + + public void setAdditionalBeanInfo(BeanInfo[] b) { + additionalBeanInfo = b; + } + + public boolean hasProperty(PropertyDescriptor p) { + return properties.get(p.getName()) != null; + } + public void addProperty(PropertyDescriptor p) { + properties.put(p.getName(),p); + } + public void addIndexedProperty(IndexedPropertyDescriptor p) { + properties.put(p.getName(),p); + } + + public boolean hasEvent(EventSetDescriptor e) { + return events.get(e.getName()) != null; + } + public void addEvent(EventSetDescriptor e) { + events.put(e.getName(),e); + } + + public boolean hasMethod(MethodDescriptor m) { + for(int i=0;iExceptionListener instance on its own. + * + *

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

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

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

+ * + *

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

+ * + * @author Robert Schuster + */ +class DummyAppletContext implements AppletContext +{ + private static final Enumeration EMPTY_ENUMERATION = Collections.enumeration(Collections.EMPTY_SET); + + DummyAppletContext() + { + } + + /** Implementation is VM neutral and returns a dummy {@link AudioClip} instance + * for every URL that returns a non-null object on + * URL.openConnection(). + * + * @see java.applet.AppletContext#getAudioClip(java.net.URL) + * + * FIXME: When Java Sound API (javax.sound) is included in Classpath or URL is able to handle + * sampled sound this should be adjusted. + */ + public AudioClip getAudioClip(URL url) + { + return Applet.newAudioClip(url); + } + + /** Loads the Image instance by delegating to + * {@link java.awt.Toolkit.createImage(URL) }. + * + * @see java.applet.AppletContext#getImage(java.net.URL) + * @see java.awt.Toolkit#createImage(java.net.URL) + */ + public Image getImage(URL url) + { + return Toolkit.getDefaultToolkit().createImage(url); + } + + /** Returns null for every argument. + * + * @see java.applet.AppletContext#getApplet(java.lang.String) + */ + public Applet getApplet(String name) + { + return null; + } + + /** Returns always an empty Enumeration. + * + * @see java.applet.AppletContext#getApplets() + */ + public Enumeration getApplets() + { + return EMPTY_ENUMERATION; + } + + /** Does nothing. + * + * @see java.applet.AppletContext#showDocument(java.net.URL) + */ + public void showDocument(URL url) + { + } + + /** Does nothing. + * + * @see java.applet.AppletContext#showDocument(java.net.URL, java.lang.String) + */ + public void showDocument(URL url, String target) + { + } + + /** Does nothing. + * + * @see java.applet.AppletContext#showStatus(java.lang.String) + */ + public void showStatus(String message) + { + } + + /** Does nothing. + * + * @see java.applet.AppletContext#setStream(java.lang.String, java.io.InputStream) + */ + public void setStream(String key, InputStream stream) + throws IOException + { + throw new IOException("Dummy implementation imposes zero InputStream associations."); + } + + /** Returns null for every argument. + * + * @see java.applet.AppletContext#getStream(java.lang.String) + */ + public InputStream getStream(String key) + { + return null; + } + + /** Returns always an empty iterator. + * + * @see java.applet.AppletContext#getStreamKeys() + */ + public Iterator getStreamKeys() + { + return Collections.EMPTY_SET.iterator(); + } +} diff --git a/libjava/classpath/gnu/java/beans/DummyAppletStub.java b/libjava/classpath/gnu/java/beans/DummyAppletStub.java new file mode 100644 index 000000000..3bcb43534 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/DummyAppletStub.java @@ -0,0 +1,115 @@ +/* gnu.java.beans.DummyAppletStub + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans; + +import java.applet.AppletContext; +import java.applet.AppletStub; +import java.net.URL; + +/** Placeholder implementation of AppletStub providing no functionality. + *

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

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

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

+ * + * @author Robert Schuster + * + */ +abstract class AbstractObjectContext extends AbstractContext +{ + protected Object object; + + AbstractObjectContext() + {} + + /** Sets the result object of the Context. + * + * @param obj The result object to be set. + */ + protected final void setObject(Object obj) + { + object = obj; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#set(int, java.lang.Object) + */ + public final void set(int index, Object o) throws AssemblyException + { + try + { + Method method = + object.getClass().getMethod( + "set", + new Class[] { Integer.TYPE, Object.class }); + + method.invoke(object, new Object[] { new Integer(index), o }); + } + catch (NoSuchMethodException nsme) + { + throw new AssemblyException(nsme); + } + catch (InvocationTargetException ite) + { + throw new AssemblyException(ite.getCause()); + } + catch (IllegalAccessException iae) + { + throw new AssemblyException(iae); + } + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#get(int) + */ + public final Object get(int index) throws AssemblyException + { + try + { + Method method = + object.getClass().getMethod( + "get", + new Class[] { Integer.TYPE }); + + return method.invoke(object, new Object[] { new Integer(index)}); + } + catch (NoSuchMethodException nsme) + { + throw new AssemblyException(nsme); + } + catch (InvocationTargetException ite) + { + throw new AssemblyException(ite.getCause()); + } + catch (IllegalAccessException iae) + { + throw new AssemblyException(iae); + } + } + + public final Object getResult() + { + return object; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ArrayContext.java b/libjava/classpath/gnu/java/beans/decoder/ArrayContext.java new file mode 100644 index 000000000..bdec1c647 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ArrayContext.java @@ -0,0 +1,122 @@ +/* gnu.java.beans.decoder.ArrayContext + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +import java.lang.reflect.Array; + +/** A Context implementation for a fixed size array. The array + * elements have to be set using IndexContext instances. + * + * @author Robert Schuster + */ +class ArrayContext extends AbstractContext +{ + private Object array; + + ArrayContext(String id, Class klass, int length) + { + setId(id); + array = Array.newInstance(klass, length); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObject(Object o) throws AssemblyException + { + throw new AssemblyException(new IllegalStateException("Adding objects without an index to a fixed array is not possible.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#reportStatement() + */ + public void notifyStatement(Context outerContext) + { + // method call intentionally ignored because there is not any useful effect + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + public Object endContext(Context outerContext) throws AssemblyException + { + return array; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#subContextFailed() + */ + public boolean subContextFailed() + { + // returns false to indicate that assembling the array does not fail only because + // a subelement failed. + return false; + } + + public void set(int index, Object o) throws AssemblyException + { + try + { + Array.set(array, index, o); + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + throw new AssemblyException(aioobe); + } + } + + public Object get(int index) throws AssemblyException + { + try + { + return Array.get(array, index); + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + throw new AssemblyException(aioobe); + } + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#getResult() + */ + public Object getResult() + { + return array; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ArrayHandler.java b/libjava/classpath/gnu/java/beans/decoder/ArrayHandler.java new file mode 100644 index 000000000..28930f519 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ArrayHandler.java @@ -0,0 +1,118 @@ +/* gnu.java.beans.decoder.ArrayHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +import java.beans.ExceptionListener; +import java.util.HashMap; + +import org.xml.sax.Attributes; + +/** ArrayHandler processes the <array> tag. Depending on the existance of the 'length' attribute a Context for + * a fixed-size or growable array is created. + * + * @author Robert Schuster + */ +class ArrayHandler extends AbstractElementHandler +{ + /** Contains a mapping between a textual description of a primitive type (like "byte") and + * its corresponding wrapper class. This allows it to easily construct Array objects for + * primitive data types. + */ + private static HashMap typeMap = new HashMap(); + + static + { + typeMap.put("byte", Byte.TYPE); + typeMap.put("short", Short.TYPE); + typeMap.put("int", Integer.TYPE); + typeMap.put("long", Long.TYPE); + + typeMap.put("float", Float.TYPE); + typeMap.put("double", Double.TYPE); + + typeMap.put("boolean", Boolean.TYPE); + + typeMap.put("char", Character.TYPE); + } + + /** + * @param PersistenceParser + */ + ArrayHandler(ElementHandler parent) + { + super(parent, true); + } + + protected Context startElement(Attributes attributes, ExceptionListener exceptionListener) + throws AssemblyException, AssemblyException + { + String id = attributes.getValue("id"); + String className = attributes.getValue("class"); + + if (className != null) + { + try + { + Class klass; + + if (typeMap.containsKey(className)) + klass = (Class) typeMap.get(className); + else + klass = instantiateClass(className); + + String length = attributes.getValue("length"); + if (length != null) + // creates Array with predefined length + return new ArrayContext(id, klass, Integer.parseInt(length)); + else + // creates Array without length restriction + return new GrowableArrayContext(id, klass); + } + catch (ClassNotFoundException cnfe) + { + throw new AssemblyException(cnfe); + } + catch (NumberFormatException nfe) + { + throw new AssemblyException(nfe); + } + } + + throw new AssemblyException(new IllegalArgumentException("Missing 'class' attribute in tag.")); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/AssemblyException.java b/libjava/classpath/gnu/java/beans/decoder/AssemblyException.java new file mode 100644 index 000000000..206c5841b --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/AssemblyException.java @@ -0,0 +1,57 @@ +/* gnu.java.beans.decoder.AssemblyException + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + + +/** The AssemblyException is used to wrap the cause of problems when assembling objects. + * In all cases only the wrapped exception is given to the PersistenceParser's + * ExceptionListener instance (never the AssemblyException itself). + * + *

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

+ * + * @author Robert Schuster + */ +class AssemblyException extends Exception +{ + AssemblyException(Throwable cause) + { + super(cause); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/BooleanHandler.java b/libjava/classpath/gnu/java/beans/decoder/BooleanHandler.java new file mode 100644 index 000000000..20aed9a3f --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/BooleanHandler.java @@ -0,0 +1,67 @@ +/* gnu.java.beans.decoder.BooleanHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + + +/** Creates a Boolean instance from the character data in a <boolean> tag. + * + * @author Robert Schuster + */ +class BooleanHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + BooleanHandler(ElementHandler parent) + { + super(parent); + + // TODO Auto-generated constructor stub + } + + protected Object parse(String number) throws AssemblyException + { + if (number.equals("true")) + return Boolean.TRUE; + + if (number.equals("false")) + return Boolean.FALSE; + + throw new AssemblyException(new IllegalArgumentException("Element contained no valid boolean value.")); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ByteHandler.java b/libjava/classpath/gnu/java/beans/decoder/ByteHandler.java new file mode 100644 index 000000000..830bbc747 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ByteHandler.java @@ -0,0 +1,59 @@ +/* gnu.java.beans.decoder.ByteHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + + +/** Creates a Byte instance from the character data in a <byte> tag. + * + * @author Robert Schuster + */ +class ByteHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + ByteHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String number) throws NumberFormatException + { + return Byte.valueOf(number); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/CharHandler.java b/libjava/classpath/gnu/java/beans/decoder/CharHandler.java new file mode 100644 index 000000000..114df8b79 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/CharHandler.java @@ -0,0 +1,62 @@ +/* gnu.java.beans.decoder.CharHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + + +/** Creates a Character instance from the character data in a <char> tag. + * + * @author Robert Schuster + */ +class CharHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + CharHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String number) throws AssemblyException + { + if (number.length() > 1) + throw new AssemblyException(new IllegalArgumentException("Element contained no valid character.")); + + return new Character(number.charAt(0)); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ClassHandler.java b/libjava/classpath/gnu/java/beans/decoder/ClassHandler.java new file mode 100644 index 000000000..c67a79a48 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ClassHandler.java @@ -0,0 +1,66 @@ +/* gnu.java.beans.decoder.ClassHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + + +/** Creates a Class instance from the character data in a <class> tag. + * + * @author Robert Schuster + */ +class ClassHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + ClassHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String characters) throws AssemblyException + { + try + { + return instantiateClass(characters); + } + catch (ClassNotFoundException cnfe) + { + throw new AssemblyException(cnfe); + } + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ConstructorContext.java b/libjava/classpath/gnu/java/beans/decoder/ConstructorContext.java new file mode 100644 index 000000000..32365eef4 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ConstructorContext.java @@ -0,0 +1,102 @@ +/* gnu.java.beans.decoder.ConstructorContext + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; + +/** A ConstructorContext is a {@link Context} implementation which collects the parameters for a constructor + * call and instantiates the result object using that constructor. After that sub-contexts can invoke + * methods on the result object. + * + *

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

+ * + * @author Robert Schuster + */ +class ConstructorContext extends AbstractCreatableObjectContext +{ + private ArrayList arguments = new ArrayList(); + private Class klass; + + ConstructorContext(String id, Class newClass) + { + setId(id); + // sets superclass field + klass = newClass; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + protected void addParameterObjectImpl(Object o) + { + arguments.add(o); + } + + protected Object createObject(Context outerContext) + throws AssemblyException + { + Object[] args = arguments.toArray(); + + try + { + Constructor constructor = MethodFinder.getConstructor(klass, args); + + // instantiates object (klass field gets re-set by superclass) + return constructor.newInstance(args); + } + catch (NoSuchMethodException nsme) + { + throw new AssemblyException(nsme); + } + catch (InvocationTargetException ite) + { + throw new AssemblyException(ite.getCause()); + } + catch (IllegalAccessException iae) + { + throw new AssemblyException(iae); + } + catch (InstantiationException ie) + { + throw new AssemblyException(ie); + } + } + +} diff --git a/libjava/classpath/gnu/java/beans/decoder/Context.java b/libjava/classpath/gnu/java/beans/decoder/Context.java new file mode 100644 index 000000000..4bdbc9ce5 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/Context.java @@ -0,0 +1,137 @@ +/* gnu.java.beans.decoder.Context + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +/** A Context is the environment for an object which is being assembler. If there + * are no errors each handler creates one Context. + *

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

+ * + * @author Robert Schuster + */ +interface Context +{ + /** Adds a parameter object to the context. This method is used when + * sub-Contexts return their result. + * + * Some Contexts do not accept more than a certain amount of objects + * and throw an AssemblerException if the amount is exceeded. + * + * @param o The object added to this context. + */ + void addParameterObject(Object o) throws AssemblyException; + + /** Notifies that the next element is a statement. This can mean + * that an argument list is complete to be called. + * + */ + void notifyStatement(Context outerContext) throws AssemblyException; + + /** Notifies that the context ends and the returns the appropriate result + * object. + * + * @param outerContext + * @return + */ + Object endContext(Context outerContext) throws AssemblyException; + + /** Notifies that the assembly of a subcontext failed and returns + * whether this Context is affected in a way that it fails too. + * + * @return Whether the failure of a subcontext lets this context fail, too. + */ + boolean subContextFailed(); + + /** Calls an appropriate indexed set method if it is available or + * throws an AssemblerException if that is not allowed on this Context. + * + * The behaviour of this method is equal to List.set(int, Object). + * + * @param index Index position to be set. + * @param o Object to be set at the given index position. + * @throws AssemblerException Indexed set is not allowed or otherwise failed. + */ + void set(int index, Object o) throws AssemblyException; + + /** Calls an appropriate indexed get method if it is available or + * throws an AssemblerException if that is not allowed on this Context. + * + * The behaviour of this method is equal to List.get(int). + * + * @param index Index position of the object return. + * @throws AssemblerException Indexed get is not allowed or otherwise failed. + */ + Object get(int index) throws AssemblyException; + + /** Returns the result which was calculated by calling endContext() or reportStatement(). + * Its the handler's responsibility to care that any of these two methods was called. + * + * This is used by sub-Contexts to access this Context's result. + * + * @return + */ + Object getResult(); + + /** Gives this Context a unique id. For convenience the id may be null which means + * that no id exists at all. + * + * @param id + */ + void setId(String id); + + /** Returns this Context's unique id or null if does not have such an id. + * + * @return This Context's id or null. + */ + String getId(); + + /** Returns whether this Context is a statement (not returning result back + * to parent handler's Context) or not (= expression). + * + * @return + */ + boolean isStatement(); + + /** Sets whether this Context is a statement or not. + * + * @param b + */ + void setStatement(boolean b); +} diff --git a/libjava/classpath/gnu/java/beans/decoder/DecoderContext.java b/libjava/classpath/gnu/java/beans/decoder/DecoderContext.java new file mode 100644 index 000000000..174a3b71b --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/DecoderContext.java @@ -0,0 +1,124 @@ +/* gnu.java.beans.decoder.DecoderContext + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +import java.beans.XMLDecoder; +import java.util.ArrayList; +import java.util.Iterator; + +/** DecoderContext is a Context implementation which allows access to + * the XMLDecoder instance itself. This is used for the <java> tag. + * + * @author Robert Schuster + */ +public class DecoderContext extends AbstractContext +{ + private XMLDecoder decoder; + + public DecoderContext(XMLDecoder xmlDecoder) + { + decoder = xmlDecoder; + } + + private ArrayList objects = new ArrayList(); + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObject(Object o) throws AssemblyException + { + objects.add(o); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#reportStatement() + */ + public void notifyStatement(Context outerContext) throws AssemblyException + { + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + public Object endContext(Context outerContext) throws AssemblyException + { + return decoder; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#subContextFailed() + */ + public boolean subContextFailed() + { + return false; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#set(int, java.lang.Object) + */ + public void set(int index, Object o) throws AssemblyException + { + throw new AssemblyException(new IllegalArgumentException("Set method is not allowed in decoder context.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#get(int) + */ + public Object get(int index) throws AssemblyException + { + throw new AssemblyException(new IllegalArgumentException("Get method is not allowed in decoder context.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#getResult() + */ + public Object getResult() + { + return decoder; + } + + /** Returns an Iterator that retrieves the assembled objects. + * + * @return An Iterator retrieving assembled objects. + */ + public Iterator iterator() + { + return objects.iterator(); + } + +} diff --git a/libjava/classpath/gnu/java/beans/decoder/DoubleHandler.java b/libjava/classpath/gnu/java/beans/decoder/DoubleHandler.java new file mode 100644 index 000000000..1a14fbabf --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/DoubleHandler.java @@ -0,0 +1,59 @@ +/* gnu.java.beans.decoder.DoubleHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + + +/** Creates a Double instance from the character data in a <double> tag. + * + * @author Robert Schuster + */ +class DoubleHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + DoubleHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String number) throws NumberFormatException + { + return Double.valueOf(number); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/DummyContext.java b/libjava/classpath/gnu/java/beans/decoder/DummyContext.java new file mode 100644 index 000000000..03f209c8c --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/DummyContext.java @@ -0,0 +1,116 @@ +/* gnu.java.beans.decoder.DummyContext + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +/** The DummyContext is used as the Context implementation for the DummyHandler. It + * just prevents having a null-reference. + * + *

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

+ * + * @author Robert Schuster + */ +public class DummyContext extends AbstractContext +{ + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObject(Object o) throws AssemblyException + { + fail(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#reportStatement() + */ + public void notifyStatement(Context outerContext) throws AssemblyException + { + // intentionally ignored + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + public Object endContext(Context outerContext) throws AssemblyException + { + fail(); + return null; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#subContextFailed() + */ + public boolean subContextFailed() + { + fail(); + return false; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#set(int, java.lang.Object) + */ + public void set(int index, Object o) throws AssemblyException + { + fail(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#get(int) + */ + public Object get(int index) throws AssemblyException + { + fail(); + return null; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#getResult() + */ + public Object getResult() + { + fail(); + return null; + } + + private void fail() + { + throw new InternalError("Invoking the DummyContext is not expected" + + " - Please file a bug report at" + + " http://www/gnu.org/software/classpath/."); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/DummyHandler.java b/libjava/classpath/gnu/java/beans/decoder/DummyHandler.java new file mode 100644 index 000000000..f9c133e54 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/DummyHandler.java @@ -0,0 +1,156 @@ +/* gnu.java.beans.decoder.DummyHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +import java.beans.ExceptionListener; + +import org.xml.sax.Attributes; + +/** An ElementHandler implementation that is used as an artificial root + * element. This avoids having to check for a null element. + * + * @author Robert Schuster + */ +class DummyHandler implements ElementHandler +{ + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#start(org.xml.sax.Attributes, java.beans.ExceptionListener) + */ + public void start( + Attributes attributes, + ExceptionListener exceptionListener) + { + fail(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#end(java.beans.ExceptionListener) + */ + public void end(ExceptionListener exceptionListener) + { + fail(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#characters(char[], int, int) + */ + public void characters(char[] ch, int start, int length) + { + fail(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#isSubelementAllowed(java.lang.String) + */ + public boolean isSubelementAllowed(String subElementName) + { + return true; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#instantiateClass(java.lang.String) + */ + public Class instantiateClass(String className) + throws ClassNotFoundException + { + fail(); + return null; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#reportStatement(java.beans.ExceptionListener) + */ + public void notifyStatement(ExceptionListener exceptionListener) + { + // ignore + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#hasFailed() + */ + public boolean hasFailed() + { + return false; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#getContext() + */ + public Context getContext() + { + return new DummyContext(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#contextFailed() + */ + public void notifyContextFailed() + { + fail(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#putObject(java.lang.String, java.lang.Object) + */ + public void putObject(String objectId, Object o) + { + fail(); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.ElementHandler#getObject(java.lang.String) + */ + public Object getObject(String objectId) + { + fail(); + return null; + } + + public ElementHandler getParent() + { + fail(); + return null; + } + + private void fail() + { + throw new InternalError("Invoking the DummyHandler is not expected" + + " - Please file a bug report at " + + " http://www.gnu.org/software/classpath/."); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ElementHandler.java b/libjava/classpath/gnu/java/beans/decoder/ElementHandler.java new file mode 100644 index 000000000..12e945bbf --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ElementHandler.java @@ -0,0 +1,130 @@ +/* gnu.java.beans.decoder.ElementHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +import java.beans.ExceptionListener; + +import org.xml.sax.Attributes; + +/** ElementHandler manages a Context instance and interacts with + * its parent and child handlers. + * + * @author Robert Schuster + */ +interface ElementHandler +{ + /** Evaluates the attributes and creates a Context instance. + * If the creation of the Context instance fails the ElementHandler + * is marked as failed which may affect the parent handler other. + * + * @param attributes Attributes of the XML tag. + */ + void start(Attributes attributes, ExceptionListener exceptionListener); + + /** Post-processes the Context. + */ + void end(ExceptionListener exceptionListener); + + /** Adds characters from the body of the XML tag to the buffer. + * + * @param ch + * @param start + * @param length + * @throws SAXException + */ + void characters(char[] ch, int start, int length); + + /** Returns whether a subelement of the given name is allowed. The rules + * for evaluating this are derived from the javabeans.dtd which can be found + * here: Java Persistence Article. + * + * @param subElementName + * @return + */ + boolean isSubelementAllowed(String subElementName); + + /** Provides the same functionality as Class.forName() but allows the decoder + * to use a different class loader. + * + * @param className + * @return + * @throws ClassNotFoundException + */ + Class instantiateClass(String className) throws ClassNotFoundException; + + /** Notifies the handler's Context that its child Context will not return + * a value back. Some Context variants need this information to know when + * a method or a constructor call can be made. + * + * This method is called by a child handler. + */ + void notifyStatement(ExceptionListener exceptionListener); + + /** Returns whether this handler has failed. + * + * This is used to skip child elements. + * + * @return Whether this handler has failed. + */ + boolean hasFailed(); + + /** Returns the Context instance this handler is working on. + * + * @return The handler's Context instance. + */ + Context getContext(); + + /** Notifies the handler that its Context failed and starts a recursive + * invocation of the parent handler if it is affected by that failure. + * + * Although the method is a public API member it is only used internally. + */ + void notifyContextFailed(); + + /** Stores the object under the given id. The object is not stored if the + * id is null. + * + * @param objectId + * @param o + */ + void putObject(String objectId, Object o); + + Object getObject(String objectId) throws AssemblyException; + + ElementHandler getParent(); +} diff --git a/libjava/classpath/gnu/java/beans/decoder/FloatHandler.java b/libjava/classpath/gnu/java/beans/decoder/FloatHandler.java new file mode 100644 index 000000000..443f38f91 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/FloatHandler.java @@ -0,0 +1,59 @@ +/* gnu.java.beans.decoder.FloatHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + + +/** Creates a Float instance from the character data in a <float> tag. + * + * @author Robert Schuster + */ +class FloatHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + FloatHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String number) throws NumberFormatException + { + return Float.valueOf(number); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/GrowableArrayContext.java b/libjava/classpath/gnu/java/beans/decoder/GrowableArrayContext.java new file mode 100644 index 000000000..fb386d1d5 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/GrowableArrayContext.java @@ -0,0 +1,138 @@ +/* gnu.java.beans.decoder.GrowableArrayContext + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package gnu.java.beans.decoder; + +import java.lang.reflect.Array; + +/** A Context implementation for a growable array. The array + * elements have to be set using expressions. + * + * @author Robert Schuster + */ +class GrowableArrayContext extends AbstractContext +{ + private static final int INITIAL_SIZE = 16; + + private Class klass; + private Object array; + private int length; + + GrowableArrayContext(String id, Class newClass) + { + setId(id); + klass = newClass; + array = Array.newInstance(klass, INITIAL_SIZE); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObject(Object o) throws AssemblyException + { + if (length == Array.getLength(array)) + { + Object tmp = Array.newInstance(klass, length * 2); + System.arraycopy(array, 0, tmp, 0, length); + array = tmp; + } + + try { + Array.set(array, length++, o); + } catch(IllegalArgumentException iae) { + throw new AssemblyException(iae); + } + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#reportStatement() + */ + public void notifyStatement(Context outerContext) throws AssemblyException + { + throw new AssemblyException( + new IllegalArgumentException("Statements inside a growable array are not allowed.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + public Object endContext(Context outerContext) throws AssemblyException + { + if (length != Array.getLength(array)) + { + Object tmp = Array.newInstance(klass, length); + System.arraycopy(array, 0, tmp, 0, length); + array = tmp; + } + + return array; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#subContextFailed() + */ + public boolean subContextFailed() + { + // returns false to indicate that assembling the array does not fail only because + // a subelement failed + return false; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#set(int, java.lang.Object) + */ + public void set(int index, Object o) throws AssemblyException + { + try { + Array.set(array, index, o); + } catch(IllegalArgumentException iae) { + throw new AssemblyException(iae); + } + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#get(int) + */ + public Object get(int index) throws AssemblyException + { + return Array.get(array, index); + } + + public Object getResult() + { + return array; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/IndexContext.java b/libjava/classpath/gnu/java/beans/decoder/IndexContext.java new file mode 100644 index 000000000..b5af9019f --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/IndexContext.java @@ -0,0 +1,130 @@ +/* gnu.java.beans.decoder.IndexContext + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +/** IndexContext is Context implementation that senses whether it is an indexed get or set + * operation and invokes this operation. + * + *

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

+ * + * @author Robert Schuster + */ +class IndexContext extends AbstractContext +{ + private Object result; + private Object argument; + private int index; + private boolean isSetter; + + IndexContext(String id, int newIndex) + { + setId(id); + index = newIndex; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObject(Object o) throws AssemblyException + { + if (! isSetter) + { + argument = o; + isSetter = true; + } + else + throw new AssemblyException(new IllegalStateException("More than one argument for indiced access is not possible.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#reportStatement() + */ + public void notifyStatement(Context outerContext) throws AssemblyException + { + throw new AssemblyException(new IllegalStateException("Statements inside indiced access are not allowed.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + public Object endContext(Context outerContext) throws AssemblyException + { + if (isSetter) + { + // setter + outerContext.set(index, argument); + + return null; + } + else + // getter + return result = outerContext.get(index); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#subContextFailed() + */ + public boolean subContextFailed() + { + // returns true to indicate that indiced access assembly fails when one of its + // argument could not be assembled + return true; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#set(int, java.lang.Object) + */ + public void set(int index, Object o) throws AssemblyException + { + throw new AssemblyException(new IllegalStateException("Setter is not allowed inside indiced access.")); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#get(int) + */ + public Object get(int index) throws AssemblyException + { + throw new AssemblyException(new IllegalStateException("getter is not allowed insided indiced access.")); + } + + public Object getResult() + { + return result; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/IntHandler.java b/libjava/classpath/gnu/java/beans/decoder/IntHandler.java new file mode 100644 index 000000000..bbd3560d7 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/IntHandler.java @@ -0,0 +1,59 @@ +/* gnu.java.beans.decoder.IntHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + + +/** Creates a Integer instance from the character data in a <int> tag. + * + * @author Robert Schuster + */ +class IntHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + IntHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String number) throws NumberFormatException + { + return Integer.valueOf(number); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/JavaHandler.java b/libjava/classpath/gnu/java/beans/decoder/JavaHandler.java new file mode 100644 index 000000000..c4b4f92c5 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/JavaHandler.java @@ -0,0 +1,93 @@ +/* gnu.java.beans.decoder.JavaHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +import java.beans.ExceptionListener; +import java.util.HashMap; + +import org.xml.sax.Attributes; + +/** Wraps a DecoderContext instance. + * + * @author Robert Schuster + */ +public class JavaHandler extends AbstractElementHandler +{ + private Context context; + private HashMap objectMap = new HashMap(); + private ClassLoader classLoader; + + /** + * @param PersistenceParser + */ + JavaHandler(DummyHandler parent, Context decoderContext, + ClassLoader cl) + { + super(parent, true); + + classLoader = cl; + + context = decoderContext; + + } + + protected Context startElement(Attributes attributes, ExceptionListener exceptionListener) + throws AssemblyException + { + // may expect version and class attribute but it not used in JDK + // so we do either + return context; + } + + public Object getObject(String objectId) + { + return objectMap.get(objectId); + } + + public void putObject(String objectId, Object o) + { + if (objectId != null) + objectMap.put(objectId, o); + } + + public Class instantiateClass(String className) + throws ClassNotFoundException + { + return Class.forName(className, false, classLoader); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/LongHandler.java b/libjava/classpath/gnu/java/beans/decoder/LongHandler.java new file mode 100644 index 000000000..13e0a8dde --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/LongHandler.java @@ -0,0 +1,59 @@ +/* gnu.java.beans.decoder.LongHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + + +/** Creates a Long instance from the character data in a <long> tag. + * + * @author Robert Schuster + */ +class LongHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + LongHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String number) throws NumberFormatException + { + return Long.valueOf(number); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/MethodContext.java b/libjava/classpath/gnu/java/beans/decoder/MethodContext.java new file mode 100644 index 000000000..84eead7a0 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/MethodContext.java @@ -0,0 +1,107 @@ +/* gnu.java.beans.decoder.MethodContext + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ +package gnu.java.beans.decoder; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; + +/** MethodContext collects arguments for a method call and creates the result object + * using it. The method is called using the result object of the parent Context. + * + *

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

+ * + * @author Robert Schuster + */ +class MethodContext extends AbstractCreatableObjectContext +{ + private ArrayList arguments = new ArrayList(); + private String methodName; + + MethodContext(String id, String newMethodName) + { + setId(id); + setStatement(true); + methodName = newMethodName; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObjectImpl(Object o) + { + arguments.add(o); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + protected Object createObject(Context outerContext) + throws AssemblyException + { + Object outerObject = outerContext.getResult(); + + if (outerObject == null) + throw new AssemblyException( + new NullPointerException( + "No object to invoke method " + methodName)); + + Object[] args = arguments.toArray(); + + try + { + Method method = + MethodFinder.getMethod( + outerObject.getClass(), + methodName, + args); + return method.invoke(outerObject, args); + } + catch (NoSuchMethodException nsme) + { + throw new AssemblyException(nsme); + } + catch (InvocationTargetException ite) + { + throw new AssemblyException(ite.getCause()); + } + catch (IllegalAccessException iae) + { + throw new AssemblyException(iae); + } + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/MethodFinder.java b/libjava/classpath/gnu/java/beans/decoder/MethodFinder.java new file mode 100644 index 000000000..82783fbde --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/MethodFinder.java @@ -0,0 +1,177 @@ +/* gnu.java.beans.decoder.MethodFinder + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.util.HashMap; + +class MethodFinder +{ + /** Provides a mapping between a wrapper class and its corresponding primitive's type. */ + private static HashMap typeMapping = new HashMap(); + + static { + typeMapping.put(Byte.class, Byte.TYPE); + typeMapping.put(Short.class, Short.TYPE); + typeMapping.put(Integer.class, Integer.TYPE); + typeMapping.put(Long.class, Long.TYPE); + typeMapping.put(Float.class, Float.TYPE); + typeMapping.put(Double.class, Double.TYPE); + + typeMapping.put(Character.class, Character.TYPE); + typeMapping.put(Boolean.class, Boolean.TYPE); + } + + private MethodFinder() + { + } + + /** Searches a Method which can accept the given arguments. + * + * @param klass + * @param name + * @param arguments + * @return + * @throws NoSuchMethodException + */ + static Method getMethod(Class klass, String name, Object[] arguments) + throws NoSuchMethodException + { + // prepares array containing the types of the arguments + Class[] argumentTypes = getArgumentTypes(arguments); + + Method[] methods = klass.getMethods(); + + // iterates over all public methods + for (int i = 0; i < methods.length; i++) + { + if (methods[i].getName().equals(name)) + { + if (matchingArgumentTypes(methods[i].getParameterTypes(), + argumentTypes)) + return methods[i]; + } + } + + throw new NoSuchMethodException( + "Could not find a matching method named " + + name + + "() in class " + + klass); + } + + static Constructor getConstructor(Class klass, Object[] arguments) + throws NoSuchMethodException + { + Class[] argumentTypes = getArgumentTypes(arguments); + Constructor[] constructors = klass.getConstructors(); + + // iterates over all public methods + for (int i = 0; i < constructors.length; i++) + { + if (matchingArgumentTypes(constructors[i].getParameterTypes(), + argumentTypes)) + return constructors[i]; + } + + throw new NoSuchMethodException( + "Could not find a matching constructor in class " + klass); + } + + /** Transforms an array of argument objects into an array of argument types. + * For each argument being null the argument is null, too. An argument type + * being null means: Accepts everything (although this can be ambigous). + * + * @param arguments + * @return + */ + private static Class[] getArgumentTypes(Object[] arguments) + { + if (arguments == null) + return new Class[0]; + + // prepares array containing the types of the arguments + Class[] argumentTypes = new Class[arguments.length]; + for (int i = 0; i < arguments.length; i++) + argumentTypes[i] = + (arguments[i] == null) ? null : arguments[i].getClass(); + return argumentTypes; + } + + /** Tests whether the argument types supplied to the method argument types + * are assignable. In addition to the assignment specifications this method + * handles the primitive's wrapper classes as if they were of their + * primitive type (e.g Boolean.class equals Boolean.TYPE). + * When a supplied argument type is null it is assumed that no argument + * object was supplied for it and the test for this particular parameter will + * pass. + * + * @param methodArgTypes + * @param suppliedArgTypes + * @return + */ + private static boolean matchingArgumentTypes( + Class[] methodArgTypes, + Class[] suppliedArgTypes) + { + if (methodArgTypes.length != suppliedArgTypes.length) + return false; + + for (int i = 0; i < methodArgTypes.length; i++) + { + if (suppliedArgTypes[i] == null) + { + // by definition a non-existant argument type (null) can be converted to everything + continue; + } + else if (typeMapping.containsKey(suppliedArgTypes[i])) + { + Class primitiveType = + (Class) typeMapping.get(suppliedArgTypes[i]); + if (!(methodArgTypes[i].isAssignableFrom(suppliedArgTypes[i]) + || methodArgTypes[i].isAssignableFrom(primitiveType))) + return false; + } + else if (!methodArgTypes[i].isAssignableFrom(suppliedArgTypes[i])) + return false; + } + + return true; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/NullHandler.java b/libjava/classpath/gnu/java/beans/decoder/NullHandler.java new file mode 100644 index 000000000..01c9727d4 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/NullHandler.java @@ -0,0 +1,62 @@ +/* gnu.java.beans.decoder.NullHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + + +/** Just provides the 'null' object. + * + * @author Robert Schuster + */ +class NullHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + NullHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String characters) throws AssemblyException + { + if (! characters.equals("")) + throw new AssemblyException(new IllegalArgumentException("No characters inside tag allowed.")); + + return null; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ObjectContext.java b/libjava/classpath/gnu/java/beans/decoder/ObjectContext.java new file mode 100644 index 000000000..883c1d600 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ObjectContext.java @@ -0,0 +1,100 @@ +/* gnu.java.beans.decoder.ObjectHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +/** ObjectContext is a {@link Context} implementation that wraps a simple Object instance. + * The instance can be provided when the Context is created (due to an 'idref' + * attribute) or later (eg. <int> tag) + * + *

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

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

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

+ * + * @author Robert Schuster + */ +class PropertyContext extends AbstractObjectContext +{ + private Object argument; + private String propertyName; + private String prefix = "get"; + private boolean methodCalled; + + PropertyContext(String id, String newPropertyName) + { + setId(id); + propertyName = newPropertyName; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObject(Object o) throws AssemblyException + { + if (methodCalled) + throw new AssemblyException(new IllegalArgumentException("Cannot add parameter object when method was already called.")); + + if (argument != null) + throw new AssemblyException(new IllegalArgumentException("Property attribut allows zero or one argument only.")); + + argument = o; + setStatement(true); + prefix = "set"; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + public void notifyStatement(Context outerContext) throws AssemblyException + { + if (methodCalled) + return; + methodCalled = true; + + Object outerObject = outerContext.getResult(); + + if (outerObject == null) + throw new AssemblyException(new NullPointerException("No object to access property " + + propertyName)); + + + // converts property name into a method name + String methodName = prefix + propertyName.substring(0, 1).toUpperCase() + + propertyName.substring(1); + + // prepares the argument + Object[] args = (argument != null) ? new Object[] { argument } : null; + + try + { + Method method = MethodFinder.getMethod(outerObject.getClass(), + methodName, args); + + // stores the result whether it is available or not + setObject(method.invoke(outerObject, args)); + } + catch (NoSuchMethodException nsme) + { + throw new AssemblyException(nsme); + } + catch (InvocationTargetException ite) + { + throw new AssemblyException(ite.getCause()); + } + catch (IllegalAccessException iae) + { + throw new AssemblyException(iae); + } + } + + public Object endContext(Context outerContext) throws AssemblyException + { + notifyStatement(outerContext); + + return getResult(); + } + + public boolean subContextFailed() + { + return ! methodCalled; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/ShortHandler.java b/libjava/classpath/gnu/java/beans/decoder/ShortHandler.java new file mode 100644 index 000000000..c5de50ab9 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/ShortHandler.java @@ -0,0 +1,58 @@ +/* gnu.java.beans.decoder.ShortHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +/** Creates a Short instance from the character data in a <short> tag. + * + * @author Robert Schuster + */ +class ShortHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + ShortHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String number) throws NumberFormatException + { + return Short.valueOf(number); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/SimpleHandler.java b/libjava/classpath/gnu/java/beans/decoder/SimpleHandler.java new file mode 100644 index 000000000..1c43bb0c7 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/SimpleHandler.java @@ -0,0 +1,111 @@ +/* gnu.java.beans.decoder.SimpleHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +import java.beans.ExceptionListener; + +import org.xml.sax.Attributes; + +/** XML element handler that is specialized on tags that contains a simple string in their + * body which has to be parsed in a specific way. + *

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

+ * + * @author Robert Schuster + */ +abstract class SimpleHandler extends AbstractElementHandler +{ + private ObjectContext context; + + /** + * @param PersistenceParser + */ + SimpleHandler(ElementHandler parent) + { + super(parent, false); + + // SimpleHandler do not accept any subelements + } + + protected final Context startElement(Attributes attributes, ExceptionListener exceptionListener) + throws AssemblyException + { + + // note: simple elements should not have any attributes. We inform + // the user of this syntactical but uncritical problem by sending + // an IllegalArgumentException for each unneccessary attribute + int size = attributes.getLength(); + for (int i = 0; i < size; i++) { + String attributeName = attributes.getQName(i); + Exception e = + new IllegalArgumentException( + "Unneccessary attribute '" + + attributeName + + "' discarded."); + exceptionListener.exceptionThrown(e); + } + + return context = new ObjectContext(); + } + + public void endElement(String characters) + throws AssemblyException, AssemblyException + { + // reports the number when the character data can be parsed + try + { + context.setObject(parse(characters)); + } + catch (NumberFormatException nfe) + { + throw new AssemblyException(nfe); + } + } + + /** Returns an object that is created from the given characters. If the string is + * converted into a number a NumberFormatException is cathed and reported + * appropriately. + * + * @param characters A string of characters that has to be processed in some way. + * @return An Object instance generated from the given data. + * @throws AssemblerException When the string was invalid. + * @throws NumberFormatException When the string could not be parsed into a number. + */ + protected abstract Object parse(String characters) + throws AssemblyException, NumberFormatException; +} diff --git a/libjava/classpath/gnu/java/beans/decoder/StaticMethodContext.java b/libjava/classpath/gnu/java/beans/decoder/StaticMethodContext.java new file mode 100644 index 000000000..b2cf0e602 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/StaticMethodContext.java @@ -0,0 +1,95 @@ +/* gnu.java.beans.decoder.StaticMethodContext + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; + +/** + * @author Robert Schuster + */ +class StaticMethodContext extends AbstractCreatableObjectContext +{ + private ArrayList arguments = new ArrayList(); + private Class klass; + private String methodName; + + StaticMethodContext(String id, Class newClass, String newMethodName) + { + setId(id); + klass = newClass; + methodName = newMethodName; + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#addObject(java.lang.Object) + */ + public void addParameterObjectImpl(Object o) + { + arguments.add(o); + } + + /* (non-Javadoc) + * @see gnu.java.beans.decoder.Context#endContext(gnu.java.beans.decoder.Context) + */ + protected Object createObject(Context outerContext) + throws AssemblyException + { + Object[] args = arguments.toArray(); + + try + { + Method method = MethodFinder.getMethod(klass, methodName, args); + return method.invoke(null, args); + } + catch (NoSuchMethodException nsme) + { + throw new AssemblyException(nsme); + } + catch (InvocationTargetException ite) + { + // rethrows the reason for the InvocationTargetsException (ie. the exception in the called code) + throw new AssemblyException(ite.getCause()); + } + catch (IllegalAccessException iae) + { + throw new AssemblyException(iae); + } + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/StringHandler.java b/libjava/classpath/gnu/java/beans/decoder/StringHandler.java new file mode 100644 index 000000000..97fc57efd --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/StringHandler.java @@ -0,0 +1,54 @@ +/* gnu.java.beans.decoder.StringHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +class StringHandler extends SimpleHandler +{ + /** + * @param PersistenceParser + */ + StringHandler(ElementHandler parent) + { + super(parent); + } + + protected Object parse(String characters) + { + return characters; + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/VoidHandler.java b/libjava/classpath/gnu/java/beans/decoder/VoidHandler.java new file mode 100644 index 000000000..56f315639 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/VoidHandler.java @@ -0,0 +1,140 @@ +/* gnu.java.beans.decoder.VoidHandler + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.decoder; + +import java.beans.ExceptionListener; + +import org.xml.sax.Attributes; + +public class VoidHandler extends AbstractElementHandler +{ + /** + * @param PersistenceParser + */ + VoidHandler(ElementHandler parent) + { + super(parent, true); + } + + protected Context startElement( + Attributes attributes, + ExceptionListener exceptionListener) + throws AssemblyException + { + Context ctx = startElementImpl(attributes); + ctx.setStatement(true); + + return ctx; + } + + private Context startElementImpl(Attributes attributes) + throws AssemblyException + { + String id = attributes.getValue("id"); + String className = attributes.getValue("class"); + String methodName = attributes.getValue("method"); + String propertyName = attributes.getValue("property"); + String index = attributes.getValue("index"); + + if (className != null) + { + try + { + Class klass = instantiateClass(className); + + // class name exists which means that we are in a static context. + // so we may want to ... + // run a constructor if methodName is "new" or null + if (methodName == null || methodName.equals("new")) + // if the id is null the result cannot be by the decoder accessed but the + // constructor may have side effects (e.g. registering itself in a global registry) + return new ConstructorContext(id, klass); + + // (falling through is important!) + // run a static method on the given class (if methodName exists, which is implied already) + return new StaticMethodContext(id, klass, methodName); + } + catch (ClassNotFoundException cnfe) + { + throw new AssemblyException(cnfe); + } + } + else + { + // className does not exist which means we are in the context of + // some object and want to ... + // access an element by index + if (index != null) + { + // note: whether this resolves into get(i) or set(i, o) depends on the + // number of arguments and is decided by the ObjectAssembler + try + { + return new IndexContext(id, Integer.parseInt(index)); + } + catch (NumberFormatException nfe) + { + throw new AssemblyException(nfe); + } + } + + // access a method if methodName exists + if (methodName != null) + return new MethodContext(id, methodName); + + // (falling through is important!) + // access a property if a propertyName exists + if (propertyName != null && propertyName.length() > 0) + // this is reported as an ordinary method invocation where the propertyName is + // converted into a 'setter'-method name: convert first character of property name + // to upper case and prepend 'set' + // Note: This will be a setter-method because the tag implies that no return + // value is expected (but a side effect) + return new PropertyContext(id, propertyName); + } + + // if code reaches this point the tag has wrong attributes. The following test + // does not make it better but can provide are more specific error message for + // a common mistake: tags are not allowed to have an idref attribute + throw new AssemblyException( + new IllegalArgumentException( + (attributes.getValue("idref") == null) + ? "Missing attributes for tag" + : " does not support 'idref' attribute.")); + } +} diff --git a/libjava/classpath/gnu/java/beans/decoder/package.html b/libjava/classpath/gnu/java/beans/decoder/package.html new file mode 100644 index 000000000..8fe65eeed --- /dev/null +++ b/libjava/classpath/gnu/java/beans/decoder/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.beans.decoder + + +

+ + + diff --git a/libjava/classpath/gnu/java/beans/editors/ColorEditor.java b/libjava/classpath/gnu/java/beans/editors/ColorEditor.java new file mode 100644 index 000000000..cb69344cb --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/ColorEditor.java @@ -0,0 +1,100 @@ +/* gnu.java.beans.editors.ColorEditor + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.editors; + +import java.awt.Color; +import java.beans.PropertyEditorSupport; + +/** + ** NativeByteEditor is a property editor for the + ** byte type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class ColorEditor extends PropertyEditorSupport { + Color[] stdColors = {Color.black,Color.blue,Color.cyan, + Color.darkGray,Color.gray,Color.green, + Color.lightGray,Color.magenta,Color.orange, + Color.pink,Color.red,Color.white, + Color.yellow}; + String[] stdColorNames = {"black","blue","cyan", + "dark gray","gray","green", + "light gray","magenta","orange", + "pink","red","white", + "yellow"}; + + /** setAsText for Color checks for standard color names + ** and then checks for a #RRGGBB value or just RRGGBB, + ** both in hex. + **/ + public void setAsText(String val) throws IllegalArgumentException { + if(val.length() == 0) { + throw new IllegalArgumentException("Tried to set empty value!"); + } + for(int i=0;iTo Do: Add custom font chooser + ** component. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class FontEditor extends PropertyEditorSupport { + /** setAsText for Font calls Font.decode(). **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(Font.decode(val)); + } + + /** getAsText for Font returns a value in the format + ** expected by Font.decode(). + **/ + public String getAsText() { + Font f = (Font)getValue(); + if(f.isBold()) { + if(f.isItalic()) { + return f.getName()+"-bolditalic-"+f.getSize(); + } else { + return f.getName()+"-bold-"+f.getSize(); + } + } else if(f.isItalic()) { + return f.getName()+"-italic-"+f.getSize(); + } else { + return f.getName()+"-"+f.getSize(); + } + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/NativeBooleanEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeBooleanEditor.java new file mode 100644 index 000000000..1df94895a --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/NativeBooleanEditor.java @@ -0,0 +1,76 @@ +/* gnu.java.beans.editors.NativeBooleanEditor + Copyright (C) 1998, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeBooleanEditor is a property editor for the + ** boolean type.

+ ** + ** To Do: add support for a checkbox + ** as the custom editor. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class NativeBooleanEditor extends PropertyEditorSupport { + String[] tags = {"true","false"}; + + /** + * setAsText for boolean checks for true or false or t or f. + * "" also means false. + **/ + public void setAsText(String val) throws IllegalArgumentException { + if(val.equalsIgnoreCase("true") || val.equalsIgnoreCase("t")) { + setValue(Boolean.TRUE); + } else if(val.equalsIgnoreCase("false") || val.equalsIgnoreCase("f") || val.equals("")) { + setValue(Boolean.FALSE); + } else { + throw new IllegalArgumentException("Value must be true, false, t, f or empty."); + } + } + + + /** getAsText for boolean calls Boolean.toString(). **/ + public String getAsText() { + return getValue().toString(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/NativeByteEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeByteEditor.java new file mode 100644 index 000000000..d427a9e3f --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/NativeByteEditor.java @@ -0,0 +1,61 @@ +/* gnu.java.beans.editors.NativeByteEditor + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeByteEditor is a property editor for the + ** byte type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class NativeByteEditor extends PropertyEditorSupport { + /** setAsText for byte calls Byte.valueOf(). **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(Byte.valueOf(val)); + } + + /** getAsText for byte calls Byte.toString(). **/ + public String getAsText() { + return getValue().toString(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/NativeDoubleEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeDoubleEditor.java new file mode 100644 index 000000000..aa229fad7 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/NativeDoubleEditor.java @@ -0,0 +1,61 @@ +/* gnu.java.beans.editors.NativeDoubleEditor + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeDoubleEditor is a property editor for the + ** double type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class NativeDoubleEditor extends PropertyEditorSupport { + /** setAsText for double calls Double.valueOf(). **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(Double.valueOf(val)); + } + + /** getAsText for double calls Double.toString(). **/ + public String getAsText() { + return getValue().toString(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/NativeFloatEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeFloatEditor.java new file mode 100644 index 000000000..09f9d6b9c --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/NativeFloatEditor.java @@ -0,0 +1,61 @@ +/* gnu.java.beans.editors.NativeFloatEditor + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeFloatEditor is a property editor for the + ** float type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class NativeFloatEditor extends PropertyEditorSupport { + /** setAsText for float calls Float.valueOf(). **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(Float.valueOf(val)); + } + + /** getAsText for float calls Float.toString(). **/ + public String getAsText() { + return getValue().toString(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/NativeIntEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeIntEditor.java new file mode 100644 index 000000000..28b6a67d9 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/NativeIntEditor.java @@ -0,0 +1,61 @@ +/* gnu.java.beans.editors.NativeIntEditor + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeIntEditor is a property editor for the + ** int type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class NativeIntEditor extends PropertyEditorSupport { + /** setAsText for int calls Integer.valueOf(). **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(Integer.valueOf(val)); + } + + /** getAsText for int calls Integer.toString(). **/ + public String getAsText() { + return getValue().toString(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/NativeLongEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeLongEditor.java new file mode 100644 index 000000000..77223fbbc --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/NativeLongEditor.java @@ -0,0 +1,61 @@ +/* gnu.java.beans.editors.NativeLongEditor + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeLongEditor is a property editor for the + ** long type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class NativeLongEditor extends PropertyEditorSupport { + /** setAsText for long calls Long.valueOf(). **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(Long.valueOf(val)); + } + + /** getAsText for long calls Long.toString(). **/ + public String getAsText() { + return getValue().toString(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/NativeShortEditor.java b/libjava/classpath/gnu/java/beans/editors/NativeShortEditor.java new file mode 100644 index 000000000..1d8845bde --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/NativeShortEditor.java @@ -0,0 +1,61 @@ +/* gnu.java.beans.editors.NativeShortEditor + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeShortEditor is a property editor for the + ** short type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class NativeShortEditor extends PropertyEditorSupport { + /** setAsText for short calls Short.valueOf(). **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(Short.valueOf(val)); + } + + /** getAsText for short calls Short.toString(). **/ + public String getAsText() { + return getValue().toString(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/StringEditor.java b/libjava/classpath/gnu/java/beans/editors/StringEditor.java new file mode 100644 index 000000000..47fdce659 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/StringEditor.java @@ -0,0 +1,61 @@ +/* gnu.java.beans.editors.StringEditor + Copyright (C) 1998 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.editors; + +import java.beans.PropertyEditorSupport; + +/** + ** NativeByteEditor is a property editor for the + ** byte type. + ** + ** @author John Keiser + ** @version 1.1.0, 29 Jul 1998 + **/ + +public class StringEditor extends PropertyEditorSupport { + /** setAsText just sets the value. **/ + public void setAsText(String val) throws IllegalArgumentException { + setValue(val); + } + + /** getAsText just returns the value. **/ + public String getAsText() { + return (String)getValue(); + } +} diff --git a/libjava/classpath/gnu/java/beans/editors/TODO b/libjava/classpath/gnu/java/beans/editors/TODO new file mode 100644 index 000000000..6877f4caf --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/TODO @@ -0,0 +1,4 @@ +- write tests for all editors +- add some sort of ColorChooser as a custom editor for ColorEditor +- add a FileNameEditor +- add a FontChooser as a custom editor for FontEditor diff --git a/libjava/classpath/gnu/java/beans/editors/package.html b/libjava/classpath/gnu/java/beans/editors/package.html new file mode 100644 index 000000000..465f68d17 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/editors/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.beans.editors + + +

+ + + diff --git a/libjava/classpath/gnu/java/beans/encoder/ArrayPersistenceDelegate.java b/libjava/classpath/gnu/java/beans/encoder/ArrayPersistenceDelegate.java new file mode 100644 index 000000000..52fc45796 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/ArrayPersistenceDelegate.java @@ -0,0 +1,153 @@ +/* ArrayPersistenceDelegate.java - A PersistenceDelegate that handles arrays. + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder; + +import java.beans.Encoder; +import java.beans.Expression; +import java.beans.PersistenceDelegate; +import java.beans.Statement; + +import java.lang.reflect.Array; +import java.util.HashMap; + +public class ArrayPersistenceDelegate extends PersistenceDelegate +{ + private static final HashMap NULL_VALUES = new HashMap(); + + static + { + NULL_VALUES.put(Boolean.TYPE, Boolean.FALSE); + NULL_VALUES.put(Byte.TYPE, Byte.valueOf((byte) 0)); + NULL_VALUES.put(Short.TYPE, Short.valueOf((short) 0)); + NULL_VALUES.put(Integer.TYPE, Integer.valueOf(0)); + NULL_VALUES.put(Long.TYPE, Long.valueOf(0)); + NULL_VALUES.put(Float.TYPE, Float.valueOf(0.0f)); + NULL_VALUES.put(Double.TYPE, Double.valueOf(0.0)); + } + + protected Expression instantiate(Object oldInstance, Encoder out) + { + Class type = oldInstance.getClass().getComponentType(); + + // oldInstance is expected to be an array, then + // getClass().getComponentType() should lead + // to its component type. + assert (type != null); + + // Not handling primitive types in a special way here + // causes that Class.forName("int") is built as an Expression + // later which would cause an exception if executed. A special + // handling to avoid the execution for primitive types can be + // java.beans.Encoder.writeExpression() . + return new Expression( + oldInstance, + Array.class, + "newInstance", + new Object[] { + type, + new Integer(Array.getLength(oldInstance)) }); + } + + protected void initialize(Class type, Object oldInstance, Object newInstance, + Encoder out) + { + int length = Array.getLength(oldInstance); + + // Compares the array value against a prototypical + // null value of the array's component type in order to skip + // writing the default values of an array. + + // Note: I have no idea why the persistence delegate for arrays writes + // an Expression that reads the value and then writes a Statement that sets + // the value. However it turned out that object arrays work better with the + // get-Expression and primitive array work fine with the set-Statement. + + type = type.getComponentType(); + if (type.isPrimitive()) + { + Object nullValue = NULL_VALUES.get(type); + + for (int i = 0; i < length; i++) + { + Object oldValue = Array.get(oldInstance, i); + + if (!oldValue.equals(nullValue)) + { + out.writeExpression(new Expression(Array.class, "get", + new Object[] { oldInstance, + Integer.valueOf(i), + })); + + out.writeStatement(new Statement(Array.class, "set", + new Object[] { + oldInstance, + Integer.valueOf(i), + oldValue + })); + } + } + + } + else + { + + for (int i = 0; i < length; i++) + { + Object oldValue = Array.get(oldInstance, i); + + if (oldValue != null) + { + out.writeExpression(new Expression(Array.class, "get", + new Object[] { oldInstance, + Integer.valueOf(i), + })); + + out.writeStatement(new Statement(Array.class, "set", + new Object[] { + oldInstance, + Integer.valueOf(i), + oldValue + })); + } + } + } + + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/ClassPersistenceDelegate.java b/libjava/classpath/gnu/java/beans/encoder/ClassPersistenceDelegate.java new file mode 100644 index 000000000..1430a6dbe --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/ClassPersistenceDelegate.java @@ -0,0 +1,80 @@ +/* ClassPersistenceDelegate.java - A PersistenceDelegate for the Class type. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.encoder; + +import java.beans.Encoder; +import java.beans.Expression; +import java.beans.PersistenceDelegate; + +/**

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

+ * + *

The class resolution is always the last step when serializing a tree + * of objects. Due to the recursive nature of the algorithm we need a way + * to end the recursion. This is achieved by the implementation of this + * {@link instantiate} method. Arbitrary classes are described with a call + * to Class.forName. However for the Class class + * we call getClass() on a String.class instance. + * This in turn lead to the resolution of the String class which is always + * encoded as "".getClass(). Finally the Encoder + * treats strings in a special way so that the recursion ends here. + * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class ClassPersistenceDelegate extends PersistenceDelegate +{ + + protected Expression instantiate(Object oldInstance, Encoder out) + { + Class oldClass = (Class) oldInstance; + + // Due to the special handling of String instances in the Encoder + // this Expression does not lead to further class resolutions. + if (oldClass == String.class) + return new Expression(oldClass, "", "getClass", null); + + // This Expression will lead to the class resolution of String.class. + if (oldClass == Class.class) + return new Expression(oldClass, String.class, "getClass", null); + + // This Expression will lead to the class resolution of Class.class. + return new Expression(oldClass, Class.class, "forName", + new Object[] { oldClass.getName() }); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/CollectionPersistenceDelegate.java b/libjava/classpath/gnu/java/beans/encoder/CollectionPersistenceDelegate.java new file mode 100644 index 000000000..bdf6fda62 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/CollectionPersistenceDelegate.java @@ -0,0 +1,84 @@ +/* CollectionPersistenceDelegate.java - A PersistenceDelegate for Collection subclasses. + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder; + +import java.util.Collection; +import java.beans.Encoder; +import java.beans.Expression; +import java.beans.PersistenceDelegate; +import java.beans.Statement; + +import java.util.Iterator; + +/**

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

+ * + *

It is used for Set and List + * implementations.

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class CollectionPersistenceDelegate extends PersistenceDelegate +{ + + protected Expression instantiate(Object oldInstance, Encoder out) + { + return new Expression( + oldInstance, + oldInstance.getClass(), + "new", + null); + } + + protected void initialize(Class type, Object oldInstance, Object newInstance, + Encoder out) + { + Iterator ite = ((Collection) oldInstance).iterator(); + + while (ite.hasNext()) + { + out.writeStatement(new Statement(oldInstance, "add", + new Object[] { ite.next() })); + + } + + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/Context.java b/libjava/classpath/gnu/java/beans/encoder/Context.java new file mode 100644 index 000000000..8acc4907b --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/Context.java @@ -0,0 +1,88 @@ +/* Context.java -- Provides calling context information to ScannerStates. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.encoder; + +/** A Contect object describes the current state + * and the call number while processing the original object + * tree in the {@link ScanEngine}. + * + *

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

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class Context +{ + private String state; + + private int call; + + Context(String newState, int newCall) + { + state = newState; + call = newCall; + } + + public int hashCode() + { + int hc = 7; + hc = 31 * hc + state.hashCode(); + hc = 31 * hc + call; + + return hc; + } + + public boolean equals(Object o) + { + if (!(o instanceof Context)) + return false; + + Context that = (Context) o; + + return state.equals(that.state) + && call == that.call; + } + + public String toString() + { + return "Context [state=" + state + ", call=" + call + "]"; + } +} diff --git a/libjava/classpath/gnu/java/beans/encoder/GenericScannerState.java b/libjava/classpath/gnu/java/beans/encoder/GenericScannerState.java new file mode 100644 index 000000000..b07771dbe --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/GenericScannerState.java @@ -0,0 +1,257 @@ +/* GenericScannerState.java + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder; + +import java.util.HashMap; + +import gnu.java.beans.encoder.elements.ArrayInstantiation; +import gnu.java.beans.encoder.elements.Array_Get; +import gnu.java.beans.encoder.elements.Array_Set; +import gnu.java.beans.encoder.elements.ClassResolution; +import gnu.java.beans.encoder.elements.Element; +import gnu.java.beans.encoder.elements.List_Get; +import gnu.java.beans.encoder.elements.List_Set; +import gnu.java.beans.encoder.elements.MethodInvocation; +import gnu.java.beans.encoder.elements.NullObject; +import gnu.java.beans.encoder.elements.ObjectInstantiation; +import gnu.java.beans.encoder.elements.ObjectReference; +import gnu.java.beans.encoder.elements.PrimitiveInstantiation; +import gnu.java.beans.encoder.elements.StaticFieldAccess; +import gnu.java.beans.encoder.elements.StaticMethodInvocation; +import gnu.java.beans.encoder.elements.StringReference; + +/** + * This class is a {@link ScannerState} implementation that creates + * suitable {@link gnu.java.beans.encoder.elements.Element} instances + * for each transition variant. + * + *

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

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +class GenericScannerState extends ScannerState +{ + private int skipElements, initialSkipElements; + + final Root root; + + HashMap skipValues; + + GenericScannerState(Root newRoot) + { + root = newRoot; + } + + GenericScannerState(Root root, int skipElements) + { + this(root); + this.skipElements = initialSkipElements = skipElements; + + if (skipElements > 0) + skipValues = new HashMap(); + } + + protected void enterImpl(Context ctx) + { + if (skipValues != null) + { + Integer skip = (Integer) skipValues.get(ctx); + + if (skip == null) + { + skip = Integer.valueOf(initialSkipElements); + skipValues.put(ctx, skip); + } + + skipElements = skip.intValue(); + } + } + + void methodInvocation(String methodName) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new MethodInvocation(methodName)); + } + + void staticMethodInvocation(String className, String methodName) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new StaticMethodInvocation(className, methodName)); + } + + void staticFieldAccess(String className, String fieldName) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new StaticFieldAccess(className, fieldName)); + } + + void classResolution(String className) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new ClassResolution(className)); + } + + void objectInstantiation(String className, ObjectId objectId) + { + if (skipValues != null && skipElements > 0) + return; + + Element elem = new ObjectInstantiation(className); + elem.initId(objectId); + + root.addChild(elem); + } + + void primitiveInstantiation(String primitiveName, String valueAsString) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new PrimitiveInstantiation(primitiveName, valueAsString)); + } + + void objectArrayInstantiation(String arrayClassName, String lengthAsString, + ObjectId objectId) + { + if (skipValues != null && skipElements > 0) + return; + + Element elem = new ArrayInstantiation(arrayClassName, lengthAsString); + elem.initId(objectId); + + root.addChild(elem); + } + + void primitiveArrayInstantiation(String arrayClassName, String lengthAsString, + ObjectId objectId) + { + objectArrayInstantiation(arrayClassName, lengthAsString, objectId); + } + + void arraySet(String indexAsString) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new Array_Set(indexAsString)); + } + + void arrayGet(String indexAsString) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new Array_Get(indexAsString)); + } + + void listGet() + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new List_Get()); + } + + void listSet() + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new List_Set()); + } + + void nullObject() + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new NullObject()); + } + + void stringReference(String string) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new StringReference(string)); + } + + void objectReference(ObjectId id) + { + if (skipValues != null && skipElements > 0) + return; + + root.addChild(new ObjectReference(id)); + } + + void end() + { + if (skipValues != null) + { + if (skipElements > 0) + skipElements--; + else + { + // Finishes the Element we are constructing. + root.end(); + } + skipValues.put(context(), Integer.valueOf(skipElements)); + } + else + root.end(); + + } + + void enter() + { + + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/IgnoringScannerState.java b/libjava/classpath/gnu/java/beans/encoder/IgnoringScannerState.java new file mode 100644 index 000000000..3ec78cdf9 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/IgnoringScannerState.java @@ -0,0 +1,133 @@ +/* IgnoringScannerState.java -- A ScannerState that does nothing. + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder; + +/** A special {@link ScannerState} implementation that ignores all child + * elements. + * + *

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

+ * + *

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

+ * + *

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

+ * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +class IgnoringScannerState extends ScannerState +{ + + void methodInvocation(String methodName) + { + } + + void staticMethodInvocation(String className, String methodName) + { + } + + void staticFieldAccess(String className, String fieldName) + { + } + + void classResolution(String className) + { + } + + void objectInstantiation(String className, ObjectId objectId) + { + } + + void primitiveInstantiation(String primitiveName, String valueAsString) + { + } + + void objectArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId) + { + } + + void primitiveArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId) + { + } + + void arraySet(String indexAsString) + { + } + + void arrayGet(String indexAsString) + { + } + + void listGet() + { + } + + void listSet() + { + } + + void nullObject() + { + } + + void stringReference(String string) + { + } + + void objectReference(ObjectId id) + { + } + + void end() + { + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/MapPersistenceDelegate.java b/libjava/classpath/gnu/java/beans/encoder/MapPersistenceDelegate.java new file mode 100644 index 000000000..9ffdb5686 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/MapPersistenceDelegate.java @@ -0,0 +1,81 @@ +/* MapPersistenceDelegate.java -- A PersistenceDelegate for Map subclasses. + + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder; + +import java.util.Map; +import java.beans.Encoder; +import java.beans.Expression; +import java.beans.PersistenceDelegate; +import java.beans.Statement; + +import java.util.Iterator; + +/** + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class MapPersistenceDelegate extends PersistenceDelegate +{ + + protected Expression instantiate(Object oldInstance, Encoder out) + { + return new Expression( + oldInstance, + oldInstance.getClass(), + "new", + null); + } + + protected void initialize(Class type, Object oldInstance, Object newInstance, + Encoder out) + { + Map map = (Map) oldInstance; + Iterator ite = map.keySet().iterator(); + + while (ite.hasNext()) + { + Object key = ite.next(); + out.writeStatement(new Statement(oldInstance, "put", + new Object[] { key, map.get(key) })); + + } + + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/ObjectId.java b/libjava/classpath/gnu/java/beans/encoder/ObjectId.java new file mode 100644 index 000000000..13d75d6bb --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/ObjectId.java @@ -0,0 +1,132 @@ +/* ObjectId.java -- Simple object identification mechanism for XML encoding. + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder; + +import java.util.HashMap; + +/** + *

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

+ * + *

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

+ *

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

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

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

+ */ + public void init() + { + assert (klass != null); + + if (id != null) + return; + + Integer count = (Integer) nameIndices.get(klass); + if (count == null) + { + count = Integer.valueOf(0); + } + + if (klass.isArray()) + { + Class ct = klass.getComponentType(); + if (ct == Boolean.TYPE) + id = "booleanArray" + count.intValue(); + else if (ct == Byte.TYPE) + id = "byteArray" + count.intValue(); + else if (ct == Short.TYPE) + id = "shortArray" + count.intValue(); + else if (ct == Integer.TYPE) + id = "intArray" + count.intValue(); + else if (ct == Long.TYPE) + id = "longArray" + count.intValue(); + else if (ct == Float.TYPE) + id = "floatArray" + count.intValue(); + else if (ct == Double.TYPE) + id = "doubleArray" + count.intValue(); + } + else + id = klass.getName() + count.intValue(); + + nameIndices.put(klass, Integer.valueOf(count.intValue() + 1)); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/PrimitivePersistenceDelegate.java b/libjava/classpath/gnu/java/beans/encoder/PrimitivePersistenceDelegate.java new file mode 100644 index 000000000..55626b512 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/PrimitivePersistenceDelegate.java @@ -0,0 +1,74 @@ +/* PrimitivePersistenceDelegate.java + -- A PersistenceDelegate for primitive data types. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.beans.encoder; + +import java.beans.Encoder; +import java.beans.Expression; +import java.beans.PersistenceDelegate; + +/** + * A shared PersistenceDelegate implementation for all primitive types. + * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class PrimitivePersistenceDelegate extends PersistenceDelegate +{ + + protected Expression instantiate(Object oldInstance, Encoder out) + { + // The implementation relies on the fact that every primitive + // wrapper class has a constructor accepting a String argument. + // By using these constructors creating a primitive instance + // depends on the String class only. + return new Expression(oldInstance, oldInstance.getClass(), "new", + new Object[] { oldInstance.toString() }); + } + + protected void initialize(Class type, Object oldInstance, Object newInstance, Encoder out) + { + // This is a hack to make serializing primitive arrays work correctly. + // Instead of modifying an existing primitive instance to make it equal + // with another instance (which is not possible because primitives are + // immutable) we create a new instance. This is against the specification + // of the initialize method but make things work fine. + out.writeExpression(new Expression(oldInstance, oldInstance.getClass(), "new", + new Object[] { oldInstance.toString() })); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/ReportingScannerState.java b/libjava/classpath/gnu/java/beans/encoder/ReportingScannerState.java new file mode 100644 index 000000000..c91bb1567 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/ReportingScannerState.java @@ -0,0 +1,131 @@ +/* ReportingScannerState.java -- A state for debugging purposes. + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder; + +/** + * A ScannerState implementation that prints useful details + * about its arguments. Use it when the XML encoding does not work correctly + * and you want to find out how things relate to each other. + * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +class ReportingScannerState extends ScannerState +{ + + void methodInvocation(String methodName) + { + System.out.println("methodInvocation: " + methodName + "()"); + } + + void staticMethodInvocation(String className, String methodName) + { + System.out.println("staticMethodInvocation: " + className + "." + methodName + "()"); + } + + void staticFieldAccess(String className, String fieldName) + { + System.out.println("staticFieldAccess: " + className + "." + fieldName); + } + + void classResolution(String className) + { + System.out.println("classResolution: " + className); + } + + void objectInstantiation(String className, ObjectId objectId) + { + System.out.println("objectInstantiation: " + className); + } + + void primitiveInstantiation(String primitiveName, String valueAsString) + { + System.out.println("primitiveInstantiation: (" + primitiveName + ") " + valueAsString); + } + + void objectArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId) + { + System.out.println("objectArrayInstantiation: new " + arrayClassName + "[" + lengthAsString + "]"); + } + + void primitiveArrayInstantiation(String arrayClassName, String lengthAsString, ObjectId objectId) + { + System.out.println("primitiveArrayInstantiation: new " + arrayClassName + "[" + lengthAsString + "]"); + } + + void arraySet(String indexAsString) + { + System.out.println("arraySet: " + indexAsString); + } + + void arrayGet(String indexAsString) + { + System.out.println("arrayGet: " + indexAsString); + } + + void listGet() + { + System.out.println("listGet"); + } + + void listSet() + { + System.out.println("listSet"); + } + + void nullObject() + { + System.out.println("nullObject"); + } + + void stringReference(String string) + { + System.out.println("stringReference: " + string); + } + + void objectReference(ObjectId id) + { + System.out.println("objectReference: " + id); + } + + void end() + { + System.out.println("-close"); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/Root.java b/libjava/classpath/gnu/java/beans/encoder/Root.java new file mode 100644 index 000000000..a6410d716 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/Root.java @@ -0,0 +1,198 @@ +/* Root.java -- The root of an object tree. + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder; + +import java.beans.XMLEncoder; +import java.util.Iterator; +import java.util.Stack; + +import gnu.java.beans.encoder.elements.Element; + +/**

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

+ * + *

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

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

Adds another child element to the tree.

+ * + *

The new element automatically becomes the current + * element.

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

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

+ * + *

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

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

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

+ * + *

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

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

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

+ * + *

Finally the Writer is flushed.

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

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

+ * + *

This element is written only once per Writer.

+ * + *

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

+ * + * @author Robert Schuster (robertschuster@fsfe.org); + * + */ + static class RootElement extends Element + { + public void writeStart(Writer writer) + { + writer.write("java", new String[] { "version", "class" }, + new String[] { System.getProperty("java.version"), + XMLEncoder.class.getName() }, false); + } + + public void writeEnd(Writer writer) + { + writer.writeEnd(false); + } + + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/ScanEngine.java b/libjava/classpath/gnu/java/beans/encoder/ScanEngine.java new file mode 100644 index 000000000..9ced143f0 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/ScanEngine.java @@ -0,0 +1,860 @@ +/* ScanEngine.java + -- Scans the input and generates an object tree that can be written as XML. + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder; + +import java.beans.Expression; +import java.beans.Statement; +import java.io.OutputStream; +import java.lang.reflect.Array; +import java.util.HashMap; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Stack; + +/**

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

+ * + *

How does it work?

+ *

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

+ * + *

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

+ * + *

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

+ * + *

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ */ + void listGet() + { + transition(ScannerState.TRANSITION_LIST_GET); + + current.listGet(); + } + + /** Event method that denotes the null value. + */ + void nullObject() + { + transition(ScannerState.TRANSITION_NULL_OBJECT); + + current.nullObject(); + } + + /** Event method that denotes a string. + * + * @param string The string that should be written. + */ + void stringReference(String string) + { + transition(ScannerState.TRANSITION_STRING_REFERENCE); + + current.stringReference(string); + } + + /** Event method that denotes a reference to an existing object. + * + * @param id The ObjectId to be used. + */ + void objectReference(ObjectId id) + { + transition(ScannerState.TRANSITION_OBJECT_REFERENCE); + + current.objectReference(id); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/ScannerState.java b/libjava/classpath/gnu/java/beans/encoder/ScannerState.java new file mode 100644 index 000000000..14d63056e --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/ScannerState.java @@ -0,0 +1,236 @@ +/* ScannerState.java + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder; + +import java.util.HashMap; + +/**

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

+ * + *

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

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

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

+ * + *

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

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

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

+ * + *

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

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

A special event that does not provoke a direct transition.

+ * + *

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

+ */ + abstract void end(); + + void enter() + { + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/StAXWriter.java b/libjava/classpath/gnu/java/beans/encoder/StAXWriter.java new file mode 100644 index 000000000..da88c5361 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/StAXWriter.java @@ -0,0 +1,233 @@ +/* StAXWriter.java + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder; + +import java.io.OutputStream; + +import javax.xml.stream.XMLOutputFactory; +import javax.xml.stream.XMLStreamException; +import javax.xml.stream.XMLStreamWriter; + +/** A {@link Writer} implementation based on the StAX API. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class StAXWriter implements Writer +{ + XMLStreamWriter writer; + + int indent = 0; + + public StAXWriter(OutputStream os) + { + try + { + XMLOutputFactory factory = XMLOutputFactory.newInstance(); + writer = factory.createXMLStreamWriter(os); + } + catch (XMLStreamException se) + { + throw (InternalError) + new InternalError( + "Could not instantiate a streaming XML writer.") + .initCause(se); + } + + } + + public void flush() + { + if (writer != null) + { + try + { + writer.flush(); + } + catch (XMLStreamException xse) + { + // TODO: find out + } + } + + } + + public void close() + { + if (writer != null) + { + try + { + writer.close(); + } + catch (XMLStreamException xse) + { + // TODO: find out + } + writer = null; + } + + } + + public void writePreamble() + { + try + { + writer.writeStartDocument("UTF-8", "1.0"); + } + catch (XMLStreamException xmlse) + { + + } + } + + public void writeEnd(boolean wasEmpty) + { + try + { + indent -= 2; + + if (wasEmpty) + return; + + for (int i = 0; i < indent; i++) + writer.writeCharacters(" "); + + writer.writeEndElement(); + + writer.writeCharacters("\n"); + } + catch (XMLStreamException xmlse) + { + + } + } + + public void writeEndNoChildren() + { + try + { + writer.writeEndElement(); + writer.writeCharacters("\n"); + } + catch (XMLStreamException xmlse) + { + + } + } + + public void write(String tagName, boolean empty) + { + write(tagName, null, null, null, empty); + } + + public void write(String tagName, String value) + { + write(tagName, value, null, null, value == null); + } + + public void writeNoChildren(String tagName, String value) + { + try + { + for (int i = 0; i < indent; i++) + writer.writeCharacters(" "); + + writer.writeStartElement(tagName); + + writer.writeCharacters(value); + } + catch (XMLStreamException xmlse) + { + + } + } + + public void write(String tagName, String attributeName, + String attributeValue, boolean empty) + { + write(tagName, null, new String[] { attributeName }, + new String[] { attributeValue }, empty); + } + + public void write(String tagName, String value, String[] attributeNames, + String[] attributeValues, boolean empty) + { + try + { + for (int i = 0; i < indent; i++) + + writer.writeCharacters(" "); + + if (empty) + writer.writeEmptyElement(tagName); + else + writer.writeStartElement(tagName); + + if (attributeNames != null) + for (int i = 0; i < attributeNames.length; i++) + writer.writeAttribute(attributeNames[i], attributeValues[i]); + + writer.writeCharacters("\n"); + + indent += 2; + + if (value != null) + { + for (int i = 0; i < indent; i++) + writer.writeCharacters(" "); + + writer.writeCharacters(value); + + writer.writeCharacters("\n"); + } + } + catch (XMLStreamException xmlse) + { + + } + } + + public void write(String tagName, String[] attributeNames, + String[] attributeValues, boolean empty) + { + write(tagName, null, attributeNames, attributeValues, empty); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/Writer.java b/libjava/classpath/gnu/java/beans/encoder/Writer.java new file mode 100644 index 000000000..e08c786d8 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/Writer.java @@ -0,0 +1,174 @@ +/* Writer.java -- Writing interface for XML persistence. + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder; + +/** A Writer represents a simplified interface to an XML + * writer that is used for the XML persistence mechanism. + * + *

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

+ * + *

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

+ * + *

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

+ * + *

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

+ * + *

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

+ * + *

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

+ * + *

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

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

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

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

+ */ + void writeEndNoChildren(); + + /** Forces the implementation to write some data. + */ + void flush(); + + /** Closes the writer. + */ + void close(); +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/ArrayInstantiation.java b/libjava/classpath/gnu/java/beans/encoder/elements/ArrayInstantiation.java new file mode 100644 index 000000000..51e00c361 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/ArrayInstantiation.java @@ -0,0 +1,74 @@ +/* ArrayInstantiation.java + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import gnu.java.beans.encoder.ObjectId; +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting the instantiation of an array. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class ArrayInstantiation extends Element +{ + final String className; + + final String lengthAsString; + + public ArrayInstantiation(String newClassName, String newLengthAsString) + { + className = newClassName; + lengthAsString = newLengthAsString; + } + + public void writeStart(Writer writer) + { + ObjectId objectId = getId(); + if (objectId.isUnused()) + writer.write("array", new String[] { "class", "length" }, + new String[] { className, lengthAsString }, isEmpty()); + else + writer.write("array", new String[] { "id", "class", "length" }, + new String[] { objectId.toString(), className, + lengthAsString }, isEmpty()); + + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/Array_Get.java b/libjava/classpath/gnu/java/beans/encoder/elements/Array_Get.java new file mode 100644 index 000000000..912ecebb5 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/Array_Get.java @@ -0,0 +1,62 @@ +/* Array_Get.java + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** + * Generates an XML element denoting the retrieval of an array value. + * + * @author Robert Schuster (robertschuster@fsfe.org) + */ +public class Array_Get extends Element +{ + final String indexAsString; + + public Array_Get(String newIndexAsString) + { + indexAsString = newIndexAsString; + } + + public void writeStart(Writer writer) + { + writer.write("void", "index", indexAsString, isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/Array_Set.java b/libjava/classpath/gnu/java/beans/encoder/elements/Array_Set.java new file mode 100644 index 000000000..096232055 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/Array_Set.java @@ -0,0 +1,57 @@ +/* Array_Set.java -- FIXME: briefly describe file purpose + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +public class Array_Set extends Element +{ + final String indexAsString; + + public Array_Set(String newIndexAsString) + { + indexAsString = newIndexAsString; + } + + public void writeStart(Writer writer) + { + writer.write("void", "index", indexAsString, isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/ClassResolution.java b/libjava/classpath/gnu/java/beans/encoder/elements/ClassResolution.java new file mode 100644 index 000000000..cb736d5c0 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/ClassResolution.java @@ -0,0 +1,67 @@ +/* ClassResolution.java + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting the resolution of a class. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class ClassResolution extends Element +{ + final String className; + + public ClassResolution(String newClassName) + { + className = newClassName; + } + + public void writeStart(Writer writer) + { + writer.writeNoChildren("class", className); + } + + public void writeEnd(Writer writer) + { + writer.writeEndNoChildren(); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/Element.java b/libjava/classpath/gnu/java/beans/encoder/elements/Element.java new file mode 100644 index 000000000..a8c0ecdf7 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/Element.java @@ -0,0 +1,157 @@ +/* Element.java -- Base class for object tree elements. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import java.util.Iterator; +import java.util.LinkedList; + +import gnu.java.beans.encoder.ObjectId; +import gnu.java.beans.encoder.Writer; + +/** Element is the base class for the object tree elements. + * + *

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

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

This can only be done once.

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

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

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

By default this does writer.writeEnd(children.isEmpty()). + * Override if neccessary, for example when using the + * {@link gnu.java.beans.encoder.Writer#writeNoChildren} method + * variants. + * + * @param writer The writer to be used for XML writing. + */ + public void writeEnd(Writer writer) + { + writer.writeEnd(children.isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/List_Get.java b/libjava/classpath/gnu/java/beans/encoder/elements/List_Get.java new file mode 100644 index 000000000..c14ab91f9 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/List_Get.java @@ -0,0 +1,56 @@ +/* List_Get.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting the retrieval of a list's element. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class List_Get extends Element +{ + + public void writeStart(Writer writer) + { + writer.write("object", "get"); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/List_Set.java b/libjava/classpath/gnu/java/beans/encoder/elements/List_Set.java new file mode 100644 index 000000000..3e7cca628 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/List_Set.java @@ -0,0 +1,56 @@ +/* List_Set.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting the setting of a list's element. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class List_Set extends Element +{ + + public void writeStart(Writer writer) + { + writer.write("object", "set"); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/MethodInvocation.java b/libjava/classpath/gnu/java/beans/encoder/elements/MethodInvocation.java new file mode 100644 index 000000000..1de5bb62d --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/MethodInvocation.java @@ -0,0 +1,62 @@ +/* MethodCall.java + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting a non-static method call. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class MethodInvocation extends Element +{ + final String methodName; + + public MethodInvocation(String newMethodName) + { + methodName = newMethodName; + } + + public void writeStart(Writer writer) + { + writer.write("void", "method", methodName, isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/NullObject.java b/libjava/classpath/gnu/java/beans/encoder/elements/NullObject.java new file mode 100644 index 000000000..211e2a74b --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/NullObject.java @@ -0,0 +1,61 @@ +/* NullObject.java + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting the null value. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class NullObject extends Element +{ + + public void writeStart(Writer writer) + { + writer.write("null", true); + } + + public void writeEnd(Writer writer) + { + writer.writeEnd(true); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/ObjectInstantiation.java b/libjava/classpath/gnu/java/beans/encoder/elements/ObjectInstantiation.java new file mode 100644 index 000000000..98614809f --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/ObjectInstantiation.java @@ -0,0 +1,68 @@ +/* ObjectInstantiation.java + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import gnu.java.beans.encoder.ObjectId; +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting the instantiation of an object. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class ObjectInstantiation extends Element +{ + final String className; + + public ObjectInstantiation(String newClassName) + { + className = newClassName; + } + + public void writeStart(Writer writer) + { + ObjectId objectId = getId(); + if (objectId.isUnused()) + writer.write("object", "class", className, isEmpty()); + else + writer.write("object", new String[] { "id", "class" }, + new String[] { objectId.toString(), className }, isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/ObjectReference.java b/libjava/classpath/gnu/java/beans/encoder/elements/ObjectReference.java new file mode 100644 index 000000000..13a597a58 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/ObjectReference.java @@ -0,0 +1,68 @@ +/* StringInstantiation.java + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import gnu.java.beans.encoder.ObjectId; +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting referencing an existing object. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class ObjectReference extends Element +{ + final ObjectId id; + + public ObjectReference(ObjectId newId) + { + id = newId; + + // Initializing the Id here is making sure it gets + // actually used. This step modifies the Id instance + // in other elements. + id.init(); + } + + public void writeStart(Writer writer) + { + writer.write("object", "idref", id.toString(), isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/PrimitiveInstantiation.java b/libjava/classpath/gnu/java/beans/encoder/elements/PrimitiveInstantiation.java new file mode 100644 index 000000000..ae34b9dad --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/PrimitiveInstantiation.java @@ -0,0 +1,69 @@ +/* PrimitiveInstantiation.java + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting a primitive data value. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class PrimitiveInstantiation extends Element +{ + final String primitiveName; + + final String valueAsString; + + public PrimitiveInstantiation(String newPrimitiveName, String newValueAsString) + { + primitiveName = newPrimitiveName; + valueAsString = newValueAsString; + } + + public void writeStart(Writer writer) + { + writer.writeNoChildren(primitiveName, valueAsString); + } + + public void writeEnd(Writer writer) + { + writer.writeEndNoChildren(); + } +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/StaticFieldAccess.java b/libjava/classpath/gnu/java/beans/encoder/elements/StaticFieldAccess.java new file mode 100644 index 000000000..7fcbf5203 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/StaticFieldAccess.java @@ -0,0 +1,66 @@ +/* StaticFieldAccess.java + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** Generates an XML element denoting a static method call. + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class StaticFieldAccess extends Element +{ + final String className; + + final String fieldName; + + public StaticFieldAccess(String newClassName, String newFieldName) + { + className = newClassName; + fieldName = newFieldName; + } + + public void writeStart(Writer writer) + { + writer.write("object", new String[] { "class", "field" }, + new String[] { className, fieldName }, isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/StaticMethodInvocation.java b/libjava/classpath/gnu/java/beans/encoder/elements/StaticMethodInvocation.java new file mode 100644 index 000000000..92d49dc41 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/StaticMethodInvocation.java @@ -0,0 +1,67 @@ +/* StaticMethodCall.java + -- A class denoting an XML element which makes up a static method call. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +/** + * + * @author Robert Schuster (robertschuster@fsfe.org) + * + */ +public class StaticMethodInvocation extends Element +{ + final String className; + + final String methodName; + + public StaticMethodInvocation(String newClassName, String newMethodName) + { + className = newClassName; + methodName = newMethodName; + } + + public void writeStart(Writer writer) + { + writer.write("void", new String[] { "class", "method" }, + new String[] { className, methodName }, isEmpty()); + } + +} diff --git a/libjava/classpath/gnu/java/beans/encoder/elements/StringReference.java b/libjava/classpath/gnu/java/beans/encoder/elements/StringReference.java new file mode 100644 index 000000000..7e6787da3 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/encoder/elements/StringReference.java @@ -0,0 +1,63 @@ +/* StringInstantiation.java + -- A class denoting an XML element which retrieves an array element. + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.beans.encoder.elements; + +import gnu.java.beans.encoder.Writer; + +public class StringReference extends Element +{ + final String string; + + public StringReference(String newString) + { + string = newString; + } + + public void writeStart(Writer writer) + { + writer.writeNoChildren("string", string); + } + + public void writeEnd(Writer writer) + { + writer.writeEndNoChildren(); + } + +} diff --git a/libjava/classpath/gnu/java/beans/package.html b/libjava/classpath/gnu/java/beans/package.html new file mode 100644 index 000000000..f3b052683 --- /dev/null +++ b/libjava/classpath/gnu/java/beans/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.beans + + +

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

+ + + diff --git a/libjava/classpath/gnu/java/lang/ArrayHelper.java b/libjava/classpath/gnu/java/lang/ArrayHelper.java new file mode 100644 index 000000000..5f675831e --- /dev/null +++ b/libjava/classpath/gnu/java/lang/ArrayHelper.java @@ -0,0 +1,78 @@ +/* ArrayHelper.java -- Helper methods for handling array operations + Copyright (C) 1998, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.lang; + +/** + * ArrayHelper helps you do things with arrays. + * + * @author John Keiser + */ +public class ArrayHelper +{ + /** + * Counterpart to java.util.Collection.contains. + * + * @param array the array to search + * @param searchFor the object to locate + * @return true if some array element equals(searchFor) + */ + public static boolean contains(Object[] array, Object searchFor) + { + return indexOf(array, searchFor) != -1; + } + + /** + * Counterpart to java.util.Collection.indexOf. + * + * @param array the array to search + * @param searchFor the object to locate + * @return the index of the first equal object, or -1 + */ + public static int indexOf(Object[] array, Object searchFor) + { + for (int i = 0; i < array.length; i++) + { + if(array[i].equals(searchFor)) + { + return i; + } + } + return -1; + } +} diff --git a/libjava/classpath/gnu/java/lang/CPStringBuilder.java b/libjava/classpath/gnu/java/lang/CPStringBuilder.java new file mode 100644 index 000000000..f42629d46 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/CPStringBuilder.java @@ -0,0 +1,1161 @@ +/* ClasspathStringBuffer.java -- Growable strings without locking or copying + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.lang; + +import gnu.classpath.SystemProperties; + +import java.io.Serializable; + +/** + * This class is based on java.lang.AbstractStringBuffer but + * without the copying of the string by toString. + * If you modify this, please consider also modifying that code. + * This code is not thread-safe; limit its use to internal use within + * methods. + */ +public final class CPStringBuilder + implements Serializable, CharSequence, Appendable +{ + + /** + * Index of next available character (and thus the size of the current + * string contents). Note that this has permissions set this way so that + * String can get the value. + * + * @serial the number of characters in the buffer + */ + private int count; + + /** + * The buffer. Note that this has permissions set this way so that String + * can get the value. + * + * @serial the buffer + */ + private char[] value; + + /** + * A flag to denote whether the string being created has been + * allocated to a {@link String} object. On construction, + * the character array, {@link #value} is referenced only + * by this class. Once {@link #toString()}, + * {@link #substring(int)} or {@link #substring(int,int)} + * are called, the array is also referenced by a {@link String} + * object and this flag is set. Subsequent modifications to + * this buffer cause a new array to be allocated and the flag + * to be reset. + */ + private boolean allocated = false; + + /** + * The default capacity of a buffer. + * This can be configured using gnu.classpath.cpstringbuilder.capacity + */ + private static final int DEFAULT_CAPACITY; + + static + { + String cap = + SystemProperties.getProperty("gnu.classpath.cpstringbuilder.capacity"); + if (cap == null) + DEFAULT_CAPACITY = 32; + else + DEFAULT_CAPACITY = Integer.parseInt(cap); + } + + /** + * Create a new CPStringBuilder with the default capacity. + */ + public CPStringBuilder() + { + this(DEFAULT_CAPACITY); + } + + /** + * Create an empty CPStringBuilder with the specified initial + * capacity. + * + * @param capacity the initial capacity + * @throws NegativeArraySizeException if capacity is negative + */ + public CPStringBuilder(int capacity) + { + value = new char[capacity]; + } + + /** + * Create a new CPStringBuilder with the characters in the + * specified String. Initial capacity will be the size of the + * String plus the default capacity. + * + * @param str the String to convert + * @throws NullPointerException if str is null + */ + public CPStringBuilder(String str) + { + count = str.length(); + value = new char[count + DEFAULT_CAPACITY]; + str.getChars(0, count, value, 0); + } + + /** + * Create a new CPStringBuilder with the characters in the + * specified StringBuffer. Initial capacity will be the size of the + * String plus the default capacity. + * + * @param str the String to convert + * @throws NullPointerException if str is null + */ + public CPStringBuilder(StringBuffer str) + { + count = str.length(); + value = new char[count + DEFAULT_CAPACITY]; + str.getChars(0, count, value, 0); + } + + /** + * Create a new CPStringBuilder with the characters in the + * specified StringBuilder. Initial capacity will be the size of the + * String plus the default capacity. + * + * @param str the String to convert + * @throws NullPointerException if str is null + */ + public CPStringBuilder(StringBuilder str) + { + count = str.length(); + value = new char[count + DEFAULT_CAPACITY]; + str.getChars(0, count, value, 0); + } + + /** + * Create a new CPStringBuilder with the characters in the + * specified CharSequence. Initial capacity will be the + * length of the sequence plus the default capacity; if the sequence + * reports a length less than or equal to 0, then the initial capacity + * will be the default. + * + * @param seq the initializing CharSequence + * @throws NullPointerException if str is null + * @since 1.5 + */ + public CPStringBuilder(CharSequence seq) + { + int len = seq.length(); + count = len <= 0 ? 0 : len; + value = new char[count + DEFAULT_CAPACITY]; + for (int i = 0; i < len; ++i) + value[i] = seq.charAt(i); + } + + /** + * Set the length of this StringBuffer. If the new length is greater than + * the current length, all the new characters are set to '\0'. If the new + * length is less than the current length, the first newLength + * characters of the old array will be preserved, and the remaining + * characters are truncated. + * + * @param newLength the new length + * @throws IndexOutOfBoundsException if the new length is negative + * (while unspecified, this is a StringIndexOutOfBoundsException) + * @see #length() + */ + public void setLength(int newLength) + { + if (newLength < 0) + throw new StringIndexOutOfBoundsException(newLength); + + int valueLength = value.length; + + /* Always call ensureCapacity in order to preserve + copy-on-write semantics, except when the position + is simply being reset + */ + if (newLength > 0) + ensureCapacity(newLength); + + if (newLength < valueLength) + { + /* If the StringBuffer's value just grew, then we know that + value is newly allocated and the region between count and + newLength is filled with '\0'. */ + count = newLength; + } + else + { + /* The StringBuffer's value doesn't need to grow. However, + we should clear out any cruft that may exist. */ + while (count < newLength) + value[count++] = '\0'; + } + } + + /** + * Get the character at the specified index. + * + * @param index the index of the character to get, starting at 0 + * @return the character at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public char charAt(int index) + { + if (index < 0 || index >= count) + throw new StringIndexOutOfBoundsException(index); + return value[index]; + } + + /** + * Get the code point at the specified index. This is like #charAt(int), + * but if the character is the start of a surrogate pair, and the + * following character completes the pair, then the corresponding + * supplementary code point is returned. + * @param index the index of the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public int codePointAt(int index) + { + return Character.codePointAt(value, index, count); + } + + /** + * Get the code point before the specified index. This is like + * #codePointAt(int), but checks the characters at index-1 and + * index-2 to see if they form a supplementary code point. + * @param index the index just past the codepoint to get, starting at 0 + * @return the codepoint at the specified index + * @throws IndexOutOfBoundsException if index is negative or >= length() + * @since 1.5 + */ + public int codePointBefore(int index) + { + // Character.codePointBefore() doesn't perform this check. We + // could use the CharSequence overload, but this is just as easy. + if (index >= count) + throw new IndexOutOfBoundsException(); + return Character.codePointBefore(value, index, 1); + } + + /** + * Get the specified array of characters. srcOffset - srcEnd + * characters will be copied into the array you pass in. + * + * @param srcOffset the index to start copying from (inclusive) + * @param srcEnd the index to stop copying from (exclusive) + * @param dst the array to copy into + * @param dstOffset the index to start copying into + * @throws NullPointerException if dst is null + * @throws IndexOutOfBoundsException if any source or target indices are + * out of range (while unspecified, source problems cause a + * StringIndexOutOfBoundsException, and dest problems cause an + * ArrayIndexOutOfBoundsException) + * @see System#arraycopy(Object, int, Object, int, int) + */ + public void getChars(int srcOffset, int srcEnd, + char[] dst, int dstOffset) + { + if (srcOffset < 0 || srcEnd > count || srcEnd < srcOffset) + throw new StringIndexOutOfBoundsException(); + System.arraycopy(value, srcOffset, dst, dstOffset, srcEnd - srcOffset); + } + + /** + * Set the character at the specified index. + * + * @param index the index of the character to set starting at 0 + * @param ch the value to set that character to + * @throws IndexOutOfBoundsException if index is negative or >= length() + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public void setCharAt(int index, char ch) + { + if (index < 0 || index >= count) + throw new StringIndexOutOfBoundsException(index); + // Call ensureCapacity to enforce copy-on-write. + ensureCapacity(count); + value[index] = ch; + } + + /** + * Append the String value of the argument to this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param obj the Object to convert and append + * @return this StringBuffer + * @see String#valueOf(Object) + * @see #append(String) + */ + public CPStringBuilder append(Object obj) + { + return append(String.valueOf(obj)); + } + + /** + * Append the String to this StringBuffer. If + * str is null, the String "null" is appended. + * + * @param str the String to append + * @return this StringBuffer + */ + public CPStringBuilder append(String str) + { + if (str == null) + str = "null"; + int len = str.length(); + ensureCapacity(count + len); + str.getChars(0, len, value, count); + count += len; + return this; + } + + /** + * Append the StringBuilder value of the argument to this + * StringBuilder. This behaves the same as + * append((Object) stringBuffer), except it is more efficient. + * + * @param stringBuffer the StringBuilder to convert and append + * @return this StringBuilder + * @see #append(Object) + */ + public CPStringBuilder append(StringBuffer stringBuffer) + { + if (stringBuffer == null) + return append("null"); + synchronized (stringBuffer) + { + int len = stringBuffer.length(); + ensureCapacity(count + len); + stringBuffer.getChars(0, len, value, count); + count += len; + } + return this; + } + + /** + * Append the char array to this StringBuffer. + * This is similar (but more efficient) than + * append(new String(data)), except in the case of null. + * + * @param data the char[] to append + * @return this StringBuffer + * @throws NullPointerException if str is null + * @see #append(char[], int, int) + */ + public CPStringBuilder append(char[] data) + { + return append(data, 0, data.length); + } + + /** + * Append part of the char array to this + * StringBuffer. This is similar (but more efficient) than + * append(new String(data, offset, count)), except in the case + * of null. + * + * @param data the char[] to append + * @param offset the start location in str + * @param count the number of characters to get from str + * @return this StringBuffer + * @throws NullPointerException if str is null + * @throws IndexOutOfBoundsException if offset or count is out of range + * (while unspecified, this is a StringIndexOutOfBoundsException) + */ + public CPStringBuilder append(char[] data, int offset, int count) + { + if (offset < 0 || count < 0 || offset > data.length - count) + throw new StringIndexOutOfBoundsException(); + ensureCapacity(this.count + count); + System.arraycopy(data, offset, value, this.count, count); + this.count += count; + return this; + } + + /** + * Append the String value of the argument to this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param bool the boolean to convert and append + * @return this StringBuffer + * @see String#valueOf(boolean) + */ + public CPStringBuilder append(boolean bool) + { + return append(bool ? "true" : "false"); + } + + /** + * Append the char to this StringBuffer. + * + * @param ch the char to append + * @return this StringBuffer + */ + public CPStringBuilder append(char ch) + { + ensureCapacity(count + 1); + value[count++] = ch; + return this; + } + + /** + * Append the characters in the CharSequence to this + * buffer. + * + * @param seq the CharSequence providing the characters + * @return this StringBuffer + * @since 1.5 + */ + public CPStringBuilder append(CharSequence seq) + { + return append(seq, 0, seq.length()); + } + + /** + * Append some characters from the CharSequence to this + * buffer. If the argument is null, the four characters "null" are + * appended. + * + * @param seq the CharSequence providing the characters + * @param start the starting index + * @param end one past the final index + * @return this StringBuffer + * @since 1.5 + */ + public CPStringBuilder append(CharSequence seq, int start, int end) + { + if (seq == null) + return append("null"); + if (end - start > 0) + { + ensureCapacity(count + end - start); + for (; start < end; ++start) + value[count++] = seq.charAt(start); + } + return this; + } + + /** + * Append the String value of the argument to this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param inum the int to convert and append + * @return this StringBuffer + * @see String#valueOf(int) + */ + // This is native in libgcj, for efficiency. + public CPStringBuilder append(int inum) + { + return append(String.valueOf(inum)); + } + + /** + * Append the String value of the argument to this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param lnum the long to convert and append + * @return this StringBuffer + * @see String#valueOf(long) + */ + public CPStringBuilder append(long lnum) + { + return append(Long.toString(lnum, 10)); + } + + /** + * Append the String value of the argument to this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param fnum the float to convert and append + * @return this StringBuffer + * @see String#valueOf(float) + */ + public CPStringBuilder append(float fnum) + { + return append(Float.toString(fnum)); + } + + /** + * Append the String value of the argument to this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param dnum the double to convert and append + * @return this StringBuffer + * @see String#valueOf(double) + */ + public CPStringBuilder append(double dnum) + { + return append(Double.toString(dnum)); + } + + /** + * Append the code point to this StringBuffer. + * This is like #append(char), but will append two characters + * if a supplementary code point is given. + * + * @param code the code point to append + * @return this StringBuffer + * @see Character#toChars(int, char[], int) + * @since 1.5 + */ + public CPStringBuilder appendCodePoint(int code) + { + int len = Character.charCount(code); + ensureCapacity(count + len); + Character.toChars(code, value, count); + count += len; + return this; + } + + /** + * Delete characters from this StringBuffer. + * delete(10, 12) will delete 10 and 11, but not 12. It is + * harmless for end to be larger than length(). + * + * @param start the first character to delete + * @param end the index after the last character to delete + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + * @since 1.2 + */ + public CPStringBuilder delete(int start, int end) + { + if (start < 0 || start > count || start > end) + throw new StringIndexOutOfBoundsException(start); + if (end > count) + end = count; + ensureCapacity(count); + if (count - end != 0) + System.arraycopy(value, end, value, start, count - end); + count -= end - start; + return this; + } + + /** + * Delete a character from this StringBuffer. + * + * @param index the index of the character to delete + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if index is out of bounds + * @since 1.2 + */ + public CPStringBuilder deleteCharAt(int index) + { + return delete(index, index + 1); + } + + /** + * Replace characters between index start (inclusive) and + * end (exclusive) with str. If end + * is larger than the size of this StringBuffer, all characters after + * start are replaced. + * + * @param start the beginning index of characters to delete (inclusive) + * @param end the ending index of characters to delete (exclusive) + * @param str the new String to insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if start or end are out of bounds + * @throws NullPointerException if str is null + * @since 1.2 + */ + public CPStringBuilder replace(int start, int end, String str) + { + if (start < 0 || start > count || start > end) + throw new StringIndexOutOfBoundsException(start); + + int len = str.length(); + // Calculate the difference in 'count' after the replace. + int delta = len - (end > count ? count : end) + start; + ensureCapacity(count + delta); + + if (delta != 0 && end < count) + System.arraycopy(value, end, value, end + delta, count - end); + + str.getChars(0, len, value, start); + count += delta; + return this; + } + + /** + * Insert a subarray of the char[] argument into this + * StringBuffer. + * + * @param offset the place to insert in this buffer + * @param str the char[] to insert + * @param str_offset the index in str to start inserting from + * @param len the number of characters to insert + * @return this StringBuffer + * @throws NullPointerException if str is null + * @throws StringIndexOutOfBoundsException if any index is out of bounds + * @since 1.2 + */ + public CPStringBuilder insert(int offset, char[] str, int str_offset, int len) + { + if (offset < 0 || offset > count || len < 0 + || str_offset < 0 || str_offset > str.length - len) + throw new StringIndexOutOfBoundsException(); + ensureCapacity(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + System.arraycopy(str, str_offset, value, offset, len); + count += len; + return this; + } + + /** + * Insert the String value of the argument into this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param offset the place to insert in this buffer + * @param obj the Object to convert and insert + * @return this StringBuffer + * @exception StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(Object) + */ + public CPStringBuilder insert(int offset, Object obj) + { + return insert(offset, obj == null ? "null" : obj.toString()); + } + + /** + * Insert the String argument into this + * StringBuffer. If str is null, the String "null" is used + * instead. + * + * @param offset the place to insert in this buffer + * @param str the String to insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public CPStringBuilder insert(int offset, String str) + { + if (offset < 0 || offset > count) + throw new StringIndexOutOfBoundsException(offset); + if (str == null) + str = "null"; + int len = str.length(); + ensureCapacity(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + str.getChars(0, len, value, offset); + count += len; + return this; + } + + /** + * Insert the CharSequence argument into this + * StringBuffer. If the sequence is null, the String + * "null" is used instead. + * + * @param offset the place to insert in this buffer + * @param sequence the CharSequence to insert + * @return this StringBuffer + * @throws IndexOutOfBoundsException if offset is out of bounds + * @since 1.5 + */ + public CPStringBuilder insert(int offset, CharSequence sequence) + { + if (sequence == null) + sequence = "null"; + return insert(offset, sequence, 0, sequence.length()); + } + + /** + * Insert a subsequence of the CharSequence argument into this + * StringBuffer. If the sequence is null, the String + * "null" is used instead. + * + * @param offset the place to insert in this buffer + * @param sequence the CharSequence to insert + * @param start the starting index of the subsequence + * @param end one past the ending index of the subsequence + * @return this StringBuffer + * @throws IndexOutOfBoundsException if offset, start, + * or end are out of bounds + * @since 1.5 + */ + public CPStringBuilder insert(int offset, CharSequence sequence, int start, int end) + { + if (sequence == null) + sequence = "null"; + if (start < 0 || end < 0 || start > end || end > sequence.length()) + throw new IndexOutOfBoundsException(); + int len = end - start; + ensureCapacity(count + len); + System.arraycopy(value, offset, value, offset + len, count - offset); + for (int i = start; i < end; ++i) + value[offset++] = sequence.charAt(i); + count += len; + return this; + } + + /** + * Insert the char[] argument into this + * StringBuffer. + * + * @param offset the place to insert in this buffer + * @param data the char[] to insert + * @return this StringBuffer + * @throws NullPointerException if data is null + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see #insert(int, char[], int, int) + */ + public CPStringBuilder insert(int offset, char[] data) + { + return insert(offset, data, 0, data.length); + } + + /** + * Insert the String value of the argument into this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param offset the place to insert in this buffer + * @param bool the boolean to convert and insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(boolean) + */ + public CPStringBuilder insert(int offset, boolean bool) + { + return insert(offset, bool ? "true" : "false"); + } + + /** + * Insert the char argument into this StringBuffer. + * + * @param offset the place to insert in this buffer + * @param ch the char to insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if offset is out of bounds + */ + public CPStringBuilder insert(int offset, char ch) + { + if (offset < 0 || offset > count) + throw new StringIndexOutOfBoundsException(offset); + ensureCapacity(count + 1); + System.arraycopy(value, offset, value, offset + 1, count - offset); + value[offset] = ch; + count++; + return this; + } + + /** + * Insert the String value of the argument into this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param offset the place to insert in this buffer + * @param inum the int to convert and insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(int) + */ + public CPStringBuilder insert(int offset, int inum) + { + return insert(offset, String.valueOf(inum)); + } + + /** + * Insert the String value of the argument into this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param offset the place to insert in this buffer + * @param lnum the long to convert and insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(long) + */ + public CPStringBuilder insert(int offset, long lnum) + { + return insert(offset, Long.toString(lnum, 10)); + } + + /** + * Insert the String value of the argument into this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param offset the place to insert in this buffer + * @param fnum the float to convert and insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(float) + */ + public CPStringBuilder insert(int offset, float fnum) + { + return insert(offset, Float.toString(fnum)); + } + + /** + * Insert the String value of the argument into this + * StringBuffer. Uses String.valueOf() to convert + * to String. + * + * @param offset the place to insert in this buffer + * @param dnum the double to convert and insert + * @return this StringBuffer + * @throws StringIndexOutOfBoundsException if offset is out of bounds + * @see String#valueOf(double) + */ + public CPStringBuilder insert(int offset, double dnum) + { + return insert(offset, Double.toString(dnum)); + } + + /** + * Finds the first instance of a substring in this StringBuilder. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @see #indexOf(String, int) + */ + public int indexOf(String str) + { + return indexOf(str, 0); + } + + /** + * Finds the first instance of a String in this StringBuffer, starting at + * a given index. If starting index is less than 0, the search starts at + * the beginning of this String. If the starting index is greater than the + * length of this String, or the substring is not found, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @since 1.4 + */ + public int indexOf(String str, int fromIndex) + { + if (fromIndex < 0) + fromIndex = 0; + int olength = str.length(); + int limit = count - olength; + String s = VMCPStringBuilder.toString(value, 0, count); + for (; fromIndex <= limit; ++fromIndex) + if (s.regionMatches(fromIndex, str, 0, olength)) + return fromIndex; + return -1; + } + + /** + * Finds the last instance of a substring in this StringBuffer. + * + * @param str String to find + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @see #lastIndexOf(String, int) + * @since 1.4 + */ + public int lastIndexOf(String str) + { + return lastIndexOf(str, count - str.length()); + } + + /** + * Finds the last instance of a String in this StringBuffer, starting at a + * given index. If starting index is greater than the maximum valid index, + * then the search begins at the end of this String. If the starting index + * is less than zero, or the substring is not found, -1 is returned. + * + * @param str String to find + * @param fromIndex index to start the search + * @return location (base 0) of the String, or -1 if not found + * @throws NullPointerException if str is null + * @since 1.4 + */ + public int lastIndexOf(String str, int fromIndex) + { + fromIndex = Math.min(fromIndex, count - str.length()); + String s = VMCPStringBuilder.toString(value, 0, count); + int olength = str.length(); + for ( ; fromIndex >= 0; fromIndex--) + if (s.regionMatches(fromIndex, str, 0, olength)) + return fromIndex; + return -1; + } + + /** + * Reverse the characters in this StringBuffer. The same sequence of + * characters exists, but in the reverse index ordering. + * + * @return this StringBuffer + */ + public CPStringBuilder reverse() + { + // Call ensureCapacity to enforce copy-on-write. + ensureCapacity(count); + for (int i = count >> 1, j = count - i; --i >= 0; ++j) + { + char c = value[i]; + value[i] = value[j]; + value[j] = c; + } + return this; + } + + /** + * This may reduce the amount of memory used by the StringBuffer, + * by resizing the internal array to remove unused space. However, + * this method is not required to resize, so this behavior cannot + * be relied upon. + * @since 1.5 + */ + public void trimToSize() + { + int wouldSave = value.length - count; + // Some random heuristics: if we save less than 20 characters, who + // cares. + if (wouldSave < 20) + return; + // If we save more than 200 characters, shrink. + // If we save more than 1/4 of the buffer, shrink. + if (wouldSave > 200 || wouldSave * 4 > value.length) + allocateArray(count); + } + + /** + * Return the number of code points between two indices in the + * StringBuffer. An unpaired surrogate counts as a + * code point for this purpose. Characters outside the indicated + * range are not examined, even if the range ends in the middle of a + * surrogate pair. + * + * @param start the starting index + * @param end one past the ending index + * @return the number of code points + * @since 1.5 + */ + public int codePointCount(int start, int end) + { + if (start < 0 || end >= count || start > end) + throw new StringIndexOutOfBoundsException(); + + int count = 0; + while (start < end) + { + char base = value[start]; + if (base < Character.MIN_HIGH_SURROGATE + || base > Character.MAX_HIGH_SURROGATE + || start == end + || start == count + || value[start + 1] < Character.MIN_LOW_SURROGATE + || value[start + 1] > Character.MAX_LOW_SURROGATE) + { + // Nothing. + } + else + { + // Surrogate pair. + ++start; + } + ++start; + ++count; + } + return count; + } + + /** + * Starting at the given index, this counts forward by the indicated + * number of code points, and then returns the resulting index. An + * unpaired surrogate counts as a single code point for this + * purpose. + * + * @param start the starting index + * @param codePoints the number of code points + * @return the resulting index + * @since 1.5 + */ + public int offsetByCodePoints(int start, int codePoints) + { + while (codePoints > 0) + { + char base = value[start]; + if (base < Character.MIN_HIGH_SURROGATE + || base > Character.MAX_HIGH_SURROGATE + || start == count + || value[start + 1] < Character.MIN_LOW_SURROGATE + || value[start + 1] > Character.MAX_LOW_SURROGATE) + { + // Nothing. + } + else + { + // Surrogate pair. + ++start; + } + ++start; + --codePoints; + } + return start; + } + + /** + * Increase the capacity of this StringBuilder. This will + * ensure that an expensive growing operation will not occur until either + * minimumCapacity is reached or the array has been allocated. + * The buffer is grown to either minimumCapacity * 2, if + * the array has been allocated or the larger of minimumCapacity and + * capacity() * 2 + 2, if it is not already large enough. + * + * @param minimumCapacity the new capacity + * @see #length() + */ + public void ensureCapacity(int minimumCapacity) + { + if (allocated || minimumCapacity > value.length) + { + if (minimumCapacity > value.length) + { + int max = value.length * 2 + 2; + minimumCapacity = (minimumCapacity < max ? max : minimumCapacity); + } + else + minimumCapacity *= 2; + allocateArray(minimumCapacity); + } + } + + /** + * Allocates a new character array. This method is triggered when + * a write is attempted after the array has been passed to a + * {@link String} object, so that the builder does not modify + * the immutable {@link String}. + * + * @param capacity the size of the new array. + */ + private void allocateArray(int capacity) + { + char[] nb = new char[capacity]; + System.arraycopy(value, 0, nb, 0, count); + value = nb; + allocated = false; + } + + /** + * Get the length of the String this StringBuilder + * would create. Not to be confused with the capacity of the + * StringBuilder. + * + * @return the length of this StringBuilder + * @see #capacity() + * @see #setLength(int) + */ + public int length() + { + return count; + } + + /** + * Creates a substring of this StringBuilder, starting at a specified index + * and ending at one character before a specified index. This is implemented + * the same as substring(beginIndex, endIndex), to satisfy + * the CharSequence interface. + * + * @param beginIndex index to start at (inclusive, base 0) + * @param endIndex index to end at (exclusive) + * @return new String which is a substring of this StringBuilder + * @throws IndexOutOfBoundsException if beginIndex or endIndex is out of + * bounds + * @see #substring(int, int) + */ + public CharSequence subSequence(int beginIndex, int endIndex) + { + return substring(beginIndex, endIndex); + } + + /** + * Creates a substring of this CPStringBuilder, starting at a specified index + * and ending at the end of this StringBuilder. + * + * @param beginIndex index to start substring (base 0) + * @return new String which is a substring of this StringBuilder + * @throws StringIndexOutOfBoundsException if beginIndex is out of bounds + * @see #substring(int, int) + */ + public String substring(int beginIndex) + { + return substring(beginIndex, count); + } + + /** + * Creates a substring of this CPStringBuilder, starting at a specified index + * and ending at one character before a specified index. + * + * @param beginIndex index to start at (inclusive, base 0) + * @param endIndex index to end at (exclusive) + * @return new String which is a substring of this StringBuilder + * @throws StringIndexOutOfBoundsException if beginIndex or endIndex is out + * of bounds + */ + public String substring(int beginIndex, int endIndex) + { + if (beginIndex < 0 || endIndex > count || endIndex < beginIndex) + throw new StringIndexOutOfBoundsException(); + int len = endIndex - beginIndex; + if (len == 0) + return ""; + allocated = true; + return VMCPStringBuilder.toString(value, beginIndex, len); + } + + /** + * Convert this CPStringBuilder to a String. The + * String is composed of the characters currently in this StringBuilder. Note + * that the result is not a copy, so we flag this here and make sure to + * allocate a new array on the next write attempt (see {@link #ensureCapacity(int)}). + * + * @return the characters in this StringBuilder + */ + public String toString() + { + allocated = true; + return VMCPStringBuilder.toString(value, 0, count); + } + +} diff --git a/libjava/classpath/gnu/java/lang/CharData.java b/libjava/classpath/gnu/java/lang/CharData.java new file mode 100644 index 000000000..cb33035e6 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/CharData.java @@ -0,0 +1,1705 @@ +/* gnu/java/lang/CharData -- Database for java.lang.Character Unicode info + Copyright (C) 2002 Free Software Foundation, Inc. + *** This file is generated by scripts/unicode-muncher.pl *** + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.lang; + +/** + * This contains the info about the unicode characters, that + * java.lang.Character needs. It is generated automatically from + * ../doc/unicode/UnicodeData-4.0.0.txt and + * ../doc/unicode/SpecialCasing-4.0.0.txt, by some + * perl scripts. These Unicode definition files can be found on the + * http://www.unicode.org website. + * JDK 1.5 uses Unicode version 4.0.0. + * + * The data is stored as string constants, but Character will convert these + * Strings to their respective char[] components. The fields + * are stored in arrays of 17 elements each, one element per Unicode plane. + * BLOCKS stores the offset of a block of 2SHIFT + * characters within DATA. The DATA field, in turn, stores + * information about each character in the low order bits, and an offset + * into the attribute tables UPPER, LOWER, + * NUM_VALUE, and DIRECTION. Notice that the + * attribute tables are much smaller than 0xffff entries; as many characters + * in Unicode share common attributes. Numbers that are too large to fit + * into NUM_VALUE as 16 bit chars are stored in LARGENUMS and a number N is + * stored in NUM_VALUE such that (-N - 3) is the offset into LARGENUMS for + * the particular character. The DIRECTION table also contains a field for + * detecting characters with multi-character uppercase expansions. + * Next, there is a listing for TITLE exceptions (most characters + * just have the same title case as upper case). Finally, there are two + * tables for multi-character capitalization, UPPER_SPECIAL + * which lists the characters which are special cased, and + * UPPER_EXPAND, which lists their expansion. + * + * @author scripts/unicode-muncher.pl (written by Jochen Hoenicke, + * Eric Blake) + * @see Character + * @see String + */ +public interface CharData +{ + /** + * The Unicode definition file that was parsed to build this database. + */ + String SOURCE = "../doc/unicode/UnicodeData-4.0.0.txt"; + + /** + * The character shift amount to look up the block offset. In other words, + * (char) (BLOCKS.value[ch >> SHIFT[p]] + ch) is the index + * where ch is described in DATA if ch + * is in Unicode plane p. Note that p is simply + * the integer division of ch and 0x10000. + */ + int[] SHIFT + = new int[] {4, 6, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 7, 8, 8}; + + /** + * The mapping of character blocks to their location in DATA. + * Each entry has been adjusted so that the 16-bit sum with the desired + * character gives the actual index into DATA. + */ + String[] BLOCKS = new String[]{ + "\017\0275\00744Z\uff90\uff9d\uff93\013" + + "\uffb5\013\004\034\025\027\007\ufff7\u00ad\u010d\uffc7" + + "\uffb7\uff7b\u0111\u0111\u00b7\u0101\uffdc\uff4a\uff37\ufef3\uff17" + + "\uff07\ufef5\uff79\u00dc2\u0141\005\uffe7\u013d\u0130\u0137" + + "\u0163\u0163\u0112\u0145\u0166\u0156\u0146\u0136\uff81\u0191\u0106" + + "\ufe84\u01ca\ufd3a\u01ba\ufd4b\u01aa\ufe74\ufd37\u014e\u01b3\ufcbb" + + "\ufcab\ufccc\ufcbc\u0173\ufcb7\ufca7\ufca8\ufc87\ufc77\ufc67\u0113" + + "\ufc47\ufc37\ufc42\ufc17\ufe0c\ufdfc\ufcd3\ufcc4\ufcbd\ufe0a\ufdfb" + + "\ufdf4\ufed5\ufec3\ufd17\ufd15\u008a\u007f\u00b5\ufdb1\u00dc\ufd6e" + + "\u00f9\u00cb\uffe3k\u00f9\ufd0f\ufcff\ufcef\ufcdf\ufccf\011" + + "\u00abi\ufffbX\ufc6f\ufd36\uffd6\ufbcc\ufbbc\ufbac\ufc0f" + + "\ufbff\uff70\ufff9\ufb5c\ufb4c\ufb3c\ufb2c\ufb1c\ufb0c\ufafc\ufaec" + + "\ufadc\ufacc\ufabc\ufaac\ufa9c\ufa8c\ufa7c\ufa6c\ufa5c\ufa4c\ufa3c" + + "\ufa2c\ufee1\ufb03\ufaf3\ufef3\ufcd4\uff0b\uff13\uf9ab\ufb8a\uf7fa" + + "\ufa69\ufbe5\ufb6e\uf90e\ufea9\ufeaf\ufb79\uf77a\uf9e9\uf8c7\ufdfc" + + "\uf760\ufb82\ufe3f\uf6e4\uf980\uf969\uf70e\ufbc6\uf764\ufda9\ufddd" + + "\ufa0a\uf67a\uf8e9\ufb48\uf68d\uf5ec\ufd91\uf6c3\uf7c4\uf75b\uf7af" + + "\uf75b\uf93b\ufade\ufb5b\ufd17\uf704\uf801\uf7e9\ufba4\ufcd7\uf72f" + + "\ufc91\uf6ac\ufb4b\uf781\uf769\ufc77\ufb71\uf99a\ufc11\uf62c\ufacb" + + "\uf701\uf6e9\ufa8f\ufbf7\uf95e\ufb91\uf5ac\ufbd4\uf3eb\uf673\uf7da" + + "\ufb87\uf832\uf53c\uf527\uf612\uf603\uf5f3\ufa8f\ufa9d\ufa29\uf4bc" + + "\uf4ac\uf2c7\uf6f4\uf678\ufab9\ufab9\uf9bf\uf43c\uf42c\ufa89\uf30a" + + "\uf6c8\uf6c4\uf4ca\uf4c3\uf89b\uf57d\uf967\uf4cd\uf4c6\uf4b9\uf264" + + "\uf34c\uf33c\uf32c\uf413\uf403\uf502\uf969\uf8b7\uf959\uf2bc\uf2ac" + + "\uf29c\uf28c\uf927\uf917\uf911\uf343\uf333\uf773\uf313\uf303\uf2f3" + + "\uf2e3\uf2d3\uf6ac\uf2b3\uf2a3\uf293\uf283\uf663\uf263\uf253\uf243" + + "\uf233\uf7f1\uf20b\uf203\uf1f3\uf1e3\uef2b\uef1b\uf1b3\uf1a3\ueeeb" + + "\uf183\uf163\ueec3\ueeb3\uf13b\uf123\uf123\uf103\uee63\uf0f3\uf0e3" + + "\uf0cb\uf4ab\uf2c3\uf3d9\uef9c\uef8c\uf073\uf063\uf053\uf043\uf033" + + "\uf5f6\uf012\uf003\ueff3\uefe3\uefd3\uefc3\uefb3\uefa3\uef93\uef83" + + "\uef73\uef63\uef53\uef43\uef33\uef23\uef13\uef03\ueef3\ueee3\ueed3" + + "\ueec3\ueeb3\ueea3\uee93\uee83\uee73\uee63\uee53\uee43\uee33\uee23" + + "\uee13\uee03\uedf3\uede3\uedd3\uedc3\ueb2d\uf374\uf176\uf156\ued73" + + "\ued63\ued53\ued43\uf279\uf307\ued05\uf2f7\uecf3\uf2e7\uecd3\uf2d7" + + "\ueca5\uf2c7\uec93\uec83\uec73\uf297\uee4c\uf292\ueb56\uf291\uf291" + + "\ueb26\uebf3\uebe3\uefda\uebc3\uebb3\uf173\ueb93\ueb83\uf201\uea6c" + + "\uea5c\uea4c\uea3c\uea2c\ueb13\ueee9\uf132\uec73\ue9f0\ueac3\uee98" + + "\uf076\ue99c\ue98c\ue97c\ue96c\ue95c\ue94c\uf0e4\uf0d4\ue91c\ue90c" + + "\ue8fc\ue8ec\ue8dc\ue8cc\ue8bc\ue8ac\ue89c\ue88c\ue87c\ue86c\ue85c" + + "\ue84c\ue83c\ue82c\ue81c\ue80c\ue7fc\ue7ec\ue7dc\ue7cc\ue7bc\ue7ac" + + "\ue79c\ue78c\ue77c\ue76c\ue75c\ue74c\ue73c\ue72c\ue71c\ue70c\ue6fc" + + "\ue6ec\ue6dc\ue6cc\ue6bc\ue6ac\ue69c\ue68c\ue67c\ue66c\ue65c\ue64c" + + "\ue63c\ue62c\ue6d0\ue6c0\ue6b4\ue6b0\ue6a0\ue690\uee5e\ue5ac\ue59c" + + "\ue58c\ue57c\ue56c\ue55c\ue54c\ue53c\ue52c\ue317\ue307\ue2f7\ue2e7" + + "\ue2d7\ue2c7\ue2b7\ue2a7\ue297\ue358\ue277\ue267\ue257\ue247\ue237" + + "\ue6e8\uecce\uecce\uecae\uec9e\uec9e\uec9e\uec6e\uec8e\uec8e\uec7e" + + "\uec6e\uec6e\ue483\uec5e\uec5e\ue165\uec4e\uec4e\ue07b\uec4d\ue053" + + "\udff6\ue71b\uec1d\uec1d\ue28c\uec0d\uec0b\ue25c\uebfb\ue607\ue22c" + + "\ue2bf\ue9a1\uea8e\ue889\uec17\ue56b\uec07\uec07\uec07\uea12\uebf7" + + "\ue914\ue906\ue8ef\ue8e4\ue8e0\ue967\ueb1b\ueb16\ue8d2\ueacf\uea9a" + + "\ue8b9\uea9c\ue8d2\ue8f5\uea66\uea63\uea30\ue87c\uea2e\uea1c\ueaa6" + + "\ue7b4\uea90\uea8b\uea81\uea71\uea61\ue10d\ue744\ue114\ue734\ue100" + + "\ue704\uea29\udf3c\udf2c\ue6c4\ue6b4\ue9d3\udeec\ue9af\udecc\ue9b1" + + "\ue99d\ue989\ue989\ue921\ue9aa\ue9a0\ue9a0\ue996\ue582\ue5c4\ue5b4" + + "\ue5a4\ue594\ue584\ue574\ue564\ue554\ue544\ue534\ue524\ue7ee\ue502" + + "\ue4f4\ue4e4\ue4dc\ue4c4\udea9\ue4a4\ue494\ue484\ue474\ue465\ue77c" + + "\ue444\ue768\ue758\udc6c\udc5c\udc4c\udc3c\udc2c\udd98\ue3b4\udd99" + + "\ue394\udd4a\ue744\udd61\udd5b\udd51\ue654\ue324\ue63b\udb5c\ue50b" + + "\ue6c4\ue2e4\ue2c4\ue2b4\ue2a4\ue294\ue284\ue274\ue264\ue254\ue244" + + "\ue234\ue224\ue214\ue204\ue1f4\ue1e4\ue1d4\ue1d4\ue1c4\ue1b4\ue1a4" + + "\ue194\ue184\ue174\ue164\ue16e\ue166\ue36c\ue1de\ue1af\ue37b\ue14f" + + "\ue0f0\ue0da\ue331\ue13d\ue149\ue094\ue147\ue2bd\ue0d9\ue28c\ue27c" + + "\ue081\ue25c\ue24c\ue03d\ue217\ue04c\ue2ec\ud80c\ud7fc\ud7ec\ud7dc" + + "\ud7cc\ud7bc\ud7ac\ud79c\ud78c\ud77c\ud76c\ud75c\ud74c\ud73c\ud72c" + + "\ud71c\ud70c\ud6fc\ud6ec\ud6dc\ud6cc\ud6bc\ud6ac\ud69c\ud68c\ud67c" + + "\ud66c\ud65c\ud64c\ud63c\ud62c\ud61c\ud60c\ud5fc\ud5ec\ud5dc\ud5cc" + + "\ud5bc\ud5ac\ud59c\ud58c\ud57c\ud56c\ud55c\ud54c\ud53c\ud52c\ud51c" + + "\ud50c\ud4fc\ud4ec\ud4dc\ud4cc\ud4bc\ud4ac\udc44\ud627\udc24\udc14" + + "\udc04\udbf4\udbe4\udf06\udbc4\udbb4\udba4\udb94\udb84\udb74\udb64" + + "\udb54\udb44\udb34\udb24\udb14\udb04\ude24\ud33c\uddfe\udeb4\udeb2" + + "\ud433\ude56\ud3d2\ud3c3\ud3b3\ud3a3\ud393\ud7bc\ud362\ud363\ud353" + + "\ud343\ud333\ud71b\ud706\ud303\ud6d9\ud2e2\ud2d3\ud2c3\ud2b3\ud2a3" + + "\ud283\ud2e7\ud273\ud833\ud15c\ud14c\ud13c\ud223\udbc1\udbb4\udc30" + + "\udb91\udc00\udc82\udb61\udb55\udbd0\udb31\udb21\udb24\udb65\udaf1" + + "\udae1\udb45\udac1\udab1\udaa1\uda91\uda81\uda71\uda61\udaba\uda41" + + "\uda31\uda21\uda11\uda01\ud9f3\ud9e1\ud9d2\ud013\ud003\ucff3\ucfe3" + + "\ucfd3\ucfc3\ucfb3\ucfa3\ucf93\ucf83\ucf73\ucf63\ucf53\ucf43\ucf33" + + "\ucf23\ucf13\ucf03\ucef3\ucee3\uced3\ucec3\uceb3\ucea3\uce93\uce83" + + "\uce73\uce63\uce53\uce43\uce33\uce23\uce13\uce03\ucdf3\ucde3\ucdd3" + + "\ucdc3\ucdb3\ucda3\ucd93\ucd83\ucd73\ucd63\ucd53\ucd43\ucd33\ucd23" + + "\ucd13\ucd03\uccf3\ucce3\uccd3\uccc3\uccb3\ucca3\ucc93\ucc83\ucc73" + + "\ucc63\ucc53\ucc43\ucc33\ucc23\ucc13\ucc03\ucbf3\ucbe3\ucbd3\ucbc3" + + "\ucbb3\ucba3\ucb93\ucb83\ucb73\ucb63\ucb53\ucb43\ucb33\ucb23\ucb13" + + "\ucb03\ucaf3\ucae3\ucad3\ucac3\ucab3\ucaa3\uca93\uca83\uca73\uca63" + + "\uca53\uca43\uca33\uca23\uca13\uca03\uc9f3\uc9e3\uc9d3\uc9c3\uc9b3" + + "\uc9a3\uc993\uc983\uc973\uc963\uc953\uc943\uc933\uc923\uc913\uc903" + + "\uc8f3\uc8e3\uc8d3\uc8c3\uc8b3\uc8a3\uc893\uc883\uc873\uc863\uc853" + + "\uc843\uc833\uc823\uc813\uc803\uc7f3\uc7e3\uc7d3\uc7c3\uc7b3\uc7a3" + + "\uc793\uc783\uc773\uc763\uc753\uc743\uc733\uc723\uc713\uc703\uc6f3" + + "\uc6e3\uc6d3\uc6c3\uc6b3\uc6a3\uc693\uc683\uc673\uc663\uc653\uc643" + + "\uc633\uc623\uc613\uc603\uc5f3\uc5e3\uc5d3\uc5c3\uc5b3\uc5a3\uc593" + + "\uc583\uc573\uc563\uc553\uc543\uc533\uc523\uc513\uc503\uc4f3\uc4e3" + + "\uc4d3\uc4c3\uc4b3\uc4a3\uc493\uc483\uc473\uc463\uc453\uc443\uc433" + + "\uc423\uc413\uc403\uc3f3\uc3e3\uc3d3\uc3c3\uc3b3\uc3a3\uc393\uc383" + + "\uc373\uc363\uc353\uc343\uc333\uc323\uc313\uc303\uc2f3\uc2e3\uc2d3" + + "\uc2c3\uc2b3\uc2a3\uc293\uc283\uc273\uc263\uc253\uc243\uc233\uc223" + + "\uc213\uc203\uc1f3\uc1e3\uc1d3\uc1c3\uc1b3\uc1a3\uc193\uc183\uc173" + + "\uc163\uc153\uc143\uc133\uc123\uc113\uc103\uc0f3\uc0e3\uc0d3\uc0c3" + + "\uc0b3\uc0a3\uc093\uc083\uc073\uc063\uc053\uc043\uc033\uc023\uc013" + + "\uc003\ubff3\ubfe3\ubfd3\ubfc3\ubfb3\ubfa3\ubf93\ubf83\ubf73\ubf63" + + "\ubf53\ubf43\ubf33\ubf23\ubf13\ubf03\ubef3\ubee3\ubed3\ubec3\ubeb3" + + "\ubea3\ube93\ube83\ube73\ube63\ube53\ube43\ube33\ube23\ube13\ube03" + + "\ubdf3\ubde3\ubdd3\ubdc3\ubdb3\ubda3\ubd93\ubd83\ubd73\ubd63\ubd53" + + "\ubd43\ubd33\ubd23\ubd13\ubd03\ubcf3\ubce3\ubcd3\ubcc3\ubcb3\ubca3" + + "\ubc93\ubc83\ubc73\ubc63\ubc53\ubc43\ubc33\ubc23\ubc13\ubc03\ubbf3" + + "\ubbe3\ubbd3\ubbc3\ubbb3\ubba3\ubb93\ubb83\ubb73\ubb63\ubb53\ubb43" + + "\ubb33\ubb23\ubb13\ubb03\ubaf3\ubae3\ubad3\ubac3\ubab3\ubaa3\uba93" + + "\uba83\uba73\uba63\uba53\uba43\uba33\uba23\uba13\uba03\ub9f3\ub9e3" + + "\ub9d3\ub9c3\ub9b3\ub9a3\ub993\ub983\ub973\ub963\ub953\ub943\ub933" + + "\ub923\ub913\ub903\ub8f3\ub8e3\ub8d3\ub8c3\ub8b3\ub8a3\ub893\ub883" + + "\ub873\ub863\ub853\ub843\ub833\ub823\ub813\ub803\ub7f3\ub7e3\ub7d3" + + "\ub7c3\ub7b3\ub7a3\ub793\ub783\ub773\ub763\ub753\ub743\ub733\ub723" + + "\ub713\ub703\ub6f3\ub6e3\ub6d3\ub6c3\ub6b3\ub6a3\ub693\ub683\ub673" + + "\ubc35\ubd04\ubcf4\ubce4\ubcd4\ub613\ub603\ub5f3\ub5e3\ub5d3\ub5c3" + + "\ub5b3\ub5a3\ub593\ub583\ub573\ub563\ub553\ub543\ub533\ub523\ub513" + + "\ub503\ub4f3\ub4e3\ub4d3\ub4c3\ub4b3\ub4a3\ub493\ub483\ub473\ub463" + + "\ub453\ub443\ub433\ub423\ub413\ub403\ub3f3\ub3e3\ub3d3\ub3c3\ub3b3" + + "\ub3a3\ub393\ub383\ub373\ub363\ub353\ub343\ub333\ub323\ub313\ub303" + + "\ub2f3\ub2e3\ub2d3\ub2c3\ub2b3\ub2a3\ub293\ub283\ub273\ub263\ub253" + + "\ub243\ub233\ub223\ub213\ub203\ub1f3\ub1e3\ub1d3\ub1c3\ub1b3\ub1a3" + + "\ub193\ub183\ub173\ub163\ub153\ub143\ub133\ub123\ub113\ub103\ub0f3" + + "\ub0e3\ub0d3\ub0c3\ub0b3\ub0a3\ub093\ub083\ub073\ub063\ub053\ub043" + + "\ub033\ub023\ub013\ub003\uaff3\uafe3\uafd3\uafc3\uafb3\uafa3\uaf93" + + "\uaf83\uaf73\uaf63\uaf53\uaf43\uaf33\uaf23\uaf13\uaf03\uaef3\uaee3" + + "\uaed3\uaec3\uaeb3\uaea3\uae93\uae83\uae73\uae63\uae53\uae43\uae33" + + "\uae23\uae13\uae03\uadf3\uade3\uadd3\uadc3\uadb3\uada3\uad93\uad83" + + "\uad73\uad63\uad53\uad43\uad33\uad23\uad13\uad03\uacf3\uace3\uacd3" + + "\uacc3\uacb3\uaca3\uac93\uac83\uac73\uac63\uac53\uac43\uac33\uac23" + + "\uac13\uac03\uabf3\uabe3\uabd3\uabc3\uabb3\uaba3\uab93\uab83\uab73" + + "\uab63\uab53\uab43\uab33\uab23\uab13\uab03\uaaf3\uaae3\uaad3\uaac3" + + "\uaab3\uaaa3\uaa93\uaa83\uaa73\uaa63\uaa53\uaa43\uaa33\uaa23\uaa13" + + "\uaa03\ua9f3\ua9e3\ua9d3\ua9c3\ua9b3\ua9a3\ua993\ua983\ua973\ua963" + + "\ua953\ua943\ua933\ua923\ua913\ua903\ua8f3\ua8e3\ua8d3\ua8c3\ua8b3" + + "\ua8a3\ua893\ua883\ua873\ua863\ua853\ua843\ua833\ua823\ua813\ua803" + + "\ua7f3\ua7e3\ua7d3\ua7c3\ua7b3\ua7a3\ua793\ua783\ua773\ua763\ua753" + + "\ua743\ua733\ua723\ua713\ua703\ua6f3\ua6e3\ua6d3\ua6c3\ua6b3\ua6a3" + + "\ua693\ua683\ua673\ua663\ua653\ua643\ua633\ua623\ua613\ua603\ua5f3" + + "\ua5e3\ua5d3\ua5c3\ua5b3\ua5a3\ua593\ua583\ua573\ua563\ua553\ua543" + + "\ua533\ua523\ua513\ua503\ua4f3\ua4e3\ua4d3\ua4c3\ua4b3\ua4a3\ua493" + + "\ua483\ua473\ua463\ua453\ua443\ua433\ua423\ua413\ua403\ua3f3\ua3e3" + + "\ua3d3\ua3c3\ua3b3\ua3a3\ua393\ua383\ua373\ua363\ua353\ua343\ua333" + + "\ua323\ua313\ua303\ua2f3\ua2e3\ua2d3\ua2c3\ua2b3\ua2a3\ua293\ua283" + + "\ua273\ua263\ua253\ua243\ua233\ua223\ua213\ua203\ua1f3\ua1e3\ua1d3" + + "\ua1c3\ua1b3\ua1a3\ua193\ua183\ua173\ua163\ua153\ua143\ua133\ua123" + + "\ua113\ua103\ua0f3\ua0e3\ua0d3\ua0c3\ua0b3\ua0a3\ua093\ua083\ua073" + + "\ua063\ua053\ua043\ua033\ua023\ua013\ua003\u9ff3\u9fe3\u9fd3\u9fc3" + + "\u9fb3\u9fa3\u9f93\u9f83\u9f73\u9f63\u9f53\u9f43\u9f33\u9f23\u9f13" + + "\u9f03\u9ef3\u9ee3\u9ed3\u9ec3\u9eb3\u9ea3\u9e93\u9e83\u9e73\u9e63" + + "\u9e53\u9e43\u9e33\u9e23\u9e13\u9e03\u9df3\u9de3\u9dd3\u9dc3\u9db3" + + "\u9da3\u9d93\u9d83\u9d73\u9d63\u9d53\u9d43\u9d33\u9d23\u9d13\u9d03" + + "\u9cf3\u9ce3\u9cd3\u9cc3\u9cb3\u9ca3\u9c93\u9c83\u9c73\u9c63\u9c53" + + "\u9c43\u9c33\u9c23\u9c13\u9c03\u9bf3\u9be3\u9bd3\u9bc3\u9bb3\u9ba3" + + "\u9b93\u9b83\u9b73\u9b63\u9b53\u9b43\u9b33\u9b23\u9b13\u9b03\u9af3" + + "\u9ae3\u9ad3\u9ac3\u9ab3\u9aa3\u9a93\u9a83\u9a73\u9a63\u9a53\u9a43" + + "\u9a33\u9a23\u9a13\u9a03\u99f3\u99e3\u99d3\u99c3\u99b3\u99a3\u9993" + + "\u9983\u9973\u9963\u9953\u9943\u9933\u9923\u9913\u9903\u98f3\u98e3" + + "\u98d3\u98c3\u98b3\u98a3\u9893\u9883\u9873\u9863\u9853\u9843\u9833" + + "\u9823\u9813\u9803\u97f3\u97e3\u97d3\u97c3\u97b3\u97a3\u9793\u9783" + + "\u9773\u9763\u9753\u9743\u9733\u9723\u9713\u9703\u96f3\u96e3\u96d3" + + "\u96c3\u96b3\u96a3\u9693\u9683\u9673\u9663\u9653\u9643\u9633\u9623" + + "\u9613\u9603\u95f3\u95e3\u95d3\u95c3\u95b3\u95a3\u9593\u9583\u9573" + + "\u9563\u9553\u9543\u9533\u9523\u9513\u9503\u94f3\u94e3\u94d3\u94c3" + + "\u94b3\u94a3\u9493\u9483\u9473\u9463\u9453\u9443\u9433\u9423\u9413" + + "\u9403\u93f3\u93e3\u93d3\u93c3\u93b3\u93a3\u9393\u9383\u9373\u9363" + + "\u9353\u9343\u9333\u9323\u9313\u9303\u92f3\u92e3\u92d3\u92c3\u92b3" + + "\u92a3\u9293\u9283\u9273\u9263\u9253\u9243\u9233\u9223\u9213\u9203" + + "\u91f3\u91e3\u91d3\u91c3\u91b3\u91a3\u9193\u9183\u9173\u9163\u9153" + + "\u9143\u9133\u9123\u9113\u9103\u90f3\u90e3\u90d3\u90c3\u90b3\u90a3" + + "\u9093\u9083\u9073\u9063\u9053\u9043\u9033\u9023\u9013\u9003\u8ff3" + + "\u8fe3\u8fd3\u8fc3\u8fb3\u8fa3\u8f93\u8f83\u8f73\u8f63\u8f53\u8f43" + + "\u8f33\u8f23\u8f13\u8f03\u8ef3\u8ee3\u8ed3\u8ec3\u8eb3\u8ea3\u8e93" + + "\u8e83\u8e73\u8e63\u8e53\u8e43\u8e33\u8e23\u8e13\u8e03\u8df3\u8de3" + + "\u8dd3\u8dc3\u8db3\u8da3\u8d93\u8d83\u8d73\u8d63\u8d53\u8d43\u8d33" + + "\u8d23\u8d13\u8d03\u8cf3\u8ce3\u8cd3\u8cc3\u8cb3\u8ca3\u8c93\u8c83" + + "\u8c73\u8c63\u8c53\u8c43\u8c33\u8c23\u8c13\u8c03\u8bf3\u8be3\u8bd3" + + "\u8bc3\u8bb3\u8ba3\u8b93\u8b83\u8b73\u8b63\u8b53\u8b43\u8b33\u8b23" + + "\u8b13\u8b03\u8af3\u8ae3\u8ad3\u8ac3\u8ab3\u8aa3\u8a93\u8a83\u8a73" + + "\u8a63\u8a53\u8a43\u8a33\u8a23\u8a13\u8a03\u89f3\u89e3\u89d3\u89c3" + + "\u89b3\u89a3\u8993\u8983\u8973\u8963\u8953\u8943\u8933\u8923\u8913" + + "\u8903\u88f3\u88e3\u88d3\u88c3\u88b3\u88a3\u8893\u8883\u8873\u8863" + + "\u8853\u8843\u8833\u8823\u8813\u8803\u87f3\u87e3\u87d3\u87c3\u87b3" + + "\u87a3\u8793\u8783\u8773\u8763\u8753\u8743\u8733\u8723\u8713\u8703" + + "\u86f3\u86e3\u86d3\u86c3\u86b3\u86a3\u8693\u8683\u8673\u8663\u8653" + + "\u8643\u8633\u8623\u8613\u8603\u85f3\u85e3\u85d3\u85c3\u85b3\u85a3" + + "\u8593\u8583\u8573\u8563\u8553\u8543\u8533\u8523\u8513\u8503\u84f3" + + "\u84e3\u84d3\u84c3\u84b3\u84a3\u8493\u8483\u8473\u8463\u8453\u8443" + + "\u8433\u8423\u8413\u8403\u83f3\u83e3\u83d3\u83c3\u83b3\u83a3\u8393" + + "\u8383\u8373\u8363\u8353\u8343\u8333\u8323\u8313\u8303\u82f3\u82e3" + + "\u82d3\u82c3\u82b3\u82a3\u8293\u8283\u8273\u8263\u8253\u8243\u8233" + + "\u8223\u8213\u8203\u81f3\u81e3\u81d3\u81c3\u81b3\u81a3\u8193\u8183" + + "\u8173\u8163\u8153\u8143\u8133\u8123\u8113\u8103\u80f3\u80e3\u80d3" + + "\u80c3\u80b3\u80a3\u8093\u8083\u8073\u8063\u8053\u8043\u8033\u8023" + + "\u8013\u8003\u7ff3\u7fe3\u7fd3\u7fc3\u7fb3\u7fa3\u7f93\u7f83\u7f73" + + "\u7f63\u7f53\u7f43\u7f33\u7f23\u7f13\u7f03\u7ef3\u7ee3\u7ed3\u7ec3" + + "\u7eb3\u7ea3\u7e93\u7e83\u7e73\u7e63\u7e53\u7e43\u7e33\u7e23\u7e13" + + "\u7e03\u7df3\u7de3\u7dd3\u7dc3\u7db3\u7da3\u7d93\u7d83\u7d73\u7d63" + + "\u7d53\u7d43\u7d33\u7d23\u7d13\u7d03\u7cf3\u7ce3\u7cd3\u7cc3\u7cb3" + + "\u7ca3\u7c93\u7c83\u7c73\u7c63\u7c53\u7c43\u7c33\u7c23\u7c13\u7c03" + + "\u7bf3\u7be3\u7bd3\u7bc3\u7bb3\u7ba3\u7b93\u7b83\u7b73\u7b63\u7b53" + + "\u7b43\u7b33\u7b23\u7b13\u7b03\u7af3\u7ae3\u7ad3\u7ac3\u7ab3\u7aa3" + + "\u7a93\u7a83\u7a73\u7a63\u7a53\u7a43\u7a33\u7a23\u7a13\u7a03\u79f3" + + "\u79e3\u79d3\u79c3\u79b3\u79a3\u7993\u7983\u7973\u7963\u7953\u7943" + + "\u7933\u7923\u7913\u7903\u78f3\u78e3\u78d3\u78c3\u78b3\u78a3\u7893" + + "\u7883\u7873\u7863\u7853\u7843\u7833\u7823\u7813\u7803\u77f3\u77e3" + + "\u77d3\u77c3\u77b3\u77a3\u7793\u7783\u7773\u7763\u7753\u7743\u7733" + + "\u7723\u7713\u7703\u76f3\u76e3\u76d3\u76c3\u76b3\u76a3\u7693\u7683" + + "\u7673\u7663\u7653\u7643\u7633\u7623\u7613\u7603\u75f3\u75e3\u75d3" + + "\u75c3\u75b3\u75a3\u7593\u7583\u7573\u7563\u7553\u7543\u7533\u7523" + + "\u7513\u7503\u74f3\u74e3\u74d3\u74c3\u74b3\u74a3\u7493\u7483\u7473" + + "\u7463\u7453\u7443\u7433\u7423\u7413\u7403\u73f3\u73e3\u73d3\u73c3" + + "\u73b3\u73a3\u7393\u7383\u7373\u7363\u7353\u7343\u7333\u7323\u7313" + + "\u7303\u72f3\u72e3\u72d3\u72c3\u72b3\u72a3\u7293\u7283\u7273\u7263" + + "\u7253\u7243\u7233\u7223\u7213\u7203\u71f3\u71e3\u71d3\u71c3\u71b3" + + "\u71a3\u7193\u7183\u7173\u7163\u7153\u7143\u7133\u7123\u7113\u7103" + + "\u70f3\u70e3\u70d3\u70c3\u70b3\u70a3\u7093\u7083\u7073\u7063\u7053" + + "\u7043\u7033\u7023\u7013\u7003\u6ff3\u6fe3\u6fd3\u6fc3\u6fb3\u6fa3" + + "\u6f93\u6f83\u6f73\u6f63\u6f53\u6f43\u6f33\u6f23\u6f13\u6f03\u6ef3" + + "\u6ee3\u6ed3\u6ec3\u6eb3\u6ea3\u6e93\u6e83\u6e73\u6e63\u6e53\u6e43" + + "\u6e33\u6e23\u6e13\u6e03\u6df3\u6de3\u6dd3\u6dc3\u6db3\u6da3\u6d93" + + "\u6d83\u6d73\u6d63\u6d53\u6d43\u6d33\u6d23\u6d13\u6d03\u6cf3\u6ce3" + + "\u6cd3\u6cc3\u6cb3\u6ca3\u6c93\u6c83\u6c73\u6c63\u6c53\u6c43\u6c33" + + "\u6c23\u6c13\u6c03\u6bf3\u6be3\u6bd3\u6bc3\u6bb3\u6ba3\u6b93\u6b83" + + "\u6b73\u6b63\u6b53\u6b43\u6b33\u6b23\u6b13\u6b03\u6af3\u6ae3\u6ad3" + + "\u6ac3\u6ab3\u6aa3\u6a93\u6a83\u6a73\u6a63\u6a53\u6a43\u6a33\u6a23" + + "\u6a13\u6a03\u69f3\u69e3\u69d3\u69c3\u69b3\u69a3\u6993\u6983\u6973" + + "\u6963\u6953\u6943\u6933\u6923\u6913\u6903\u68f3\u68e3\u68d3\u68c3" + + "\u68b3\u68a3\u6893\u6883\u6873\u6863\u6853\u6843\u6833\u6823\u6813" + + "\u6803\u67f3\u67e3\u67d3\u67c3\u67b3\u67a3\u6793\u6783\u6773\u6763" + + "\u6753\u6743\u6733\u6723\u6713\u6703\u66f3\u66e3\u66d3\u66c3\u66b3" + + "\u66a3\u6693\u6683\u6673\u6663\u6653\u6643\u6633\u6623\u6613\u6603" + + "\u65f3\u65e3\u65d3\u65c3\u65b3\u65a3\u6593\u6583\u6573\u6563\u6553" + + "\u6543\u6533\u6523\u6513\u6503\u64f3\u64e3\u64d3\u64c3\u64b3\u64a3" + + "\u6493\u6483\u6a45\u636c\u635c\u634c\u633c\u632c\u6413\u6403\u63f3" + + "\u63e3\u63d3\u63c3\u63b3\u63a3\u6393\u6383\u6373\u6363\u6353\u6343" + + "\u6333\u6323\u6313\u6303\u62f3\u62e3\u62d3\u62c3\u62b3\u62a3\u6293" + + "\u6283\u6273\u6263\u6253\u6243\u6233\u6223\u6213\u6203\u61f3\u61e3" + + "\u61d3\u61c3\u61b3\u61a3\u6193\u6183\u6173\u6163\u6153\u6143\u6133" + + "\u6123\u6113\u6103\u60f3\u60e3\u60d3\u60c3\u60b3\u60a3\u6093\u6083" + + "\u6073\u6063\u6053\u6043\u6033\u6023\u6013\u6003\u5ff3\u5fe3\u5fd3" + + "\u5fc3\u5fb3\u5fa3\u6379\u6634\u6624\u6614\u6933\u5e4c\u5e3c\u5e2c" + + "\u5e1c\u5e0c\u5dfc\u5dec\u5ddc\u5dcc\u5dbc\u5dac\u5d9c\u5d8c\u5d7c" + + "\u5d6c\u5d5c\u5d4c\u5d3c\u5d2c\u5d1c\u5d0c\u5cfc\u5cec\u5cdc\u5ccc" + + "\u5cbc\u5cac\u5c9c\u5c8c\u5c7c\u5c6c\u5c5c\u5c4c\u5c3c\u5c2c\u5c1c" + + "\u5c0c\u5bfc\u5bec\u5bdc\u5bcc\u5bbc\u5bac\u5b9c\u5b8c\u5b7c\u5b6c" + + "\u5b5c\u5b4c\u5b3c\u5b2c\u5b1c\u5b0c\u5afc\u5aec\u5adc\u5acc\u5abc" + + "\u5aac\u5a9c\u5a8c\u5a7c\u5a6c\u5a5c\u5a4c\u5a3c\u5a2c\u5a1c\u5a0c" + + "\u59fc\u59ec\u59dc\u59cc\u59bc\u59ac\u599c\u598c\u597c\u596c\u595c" + + "\u594c\u593c\u592c\u591c\u590c\u58fc\u58ec\u58dc\u58cc\u58bc\u58ac" + + "\u589c\u588c\u587c\u586c\u585c\u584c\u583c\u582c\u581c\u580c\u57fc" + + "\u57ec\u57dc\u57cc\u57bc\u57ac\u579c\u578c\u577c\u576c\u575c\u574c" + + "\u573c\u572c\u5813\u5803\u57f3\u57e3\u57d3\u57c3\u57b3\u57a3\u5793" + + "\u5783\u5773\u5763\u5753\u5743\u5733\u5723\u5713\u5703\u56f3\u56e3" + + "\u56d3\u56c3\u56b3\u56a3\u5693\u5683\u5673\u5663\u5653\u5643\u5633" + + "\u5623\u5613\u5603\u55f3\u55e3\u55d3\u55c3\u55b3\u55a3\u5593\u5583" + + "\u5573\u5563\u5553\u5543\u5533\u5523\u5513\u5503\u54f3\u54e3\u54d3" + + "\u54c3\u54b3\u54a3\u5493\u5483\u5473\u5463\u5453\u5443\u5433\u5423" + + "\u5413\u5403\u53f3\u53e3\u53d3\u53c3\u53b3\u53a3\u5393\u5383\u5373" + + "\u5363\u5353\u5343\u5333\u5323\u5313\u5303\u52f3\u52e3\u52d3\u52c3" + + "\u52b3\u52a3\u5293\u5283\u5273\u5263\u5253\u5243\u5233\u5223\u5213" + + "\u5203\u51f3\u51e3\u51d3\u51c3\u51b3\u51a3\u5193\u5183\u5173\u5163" + + "\u5153\u5143\u5133\u5123\u5113\u5103\u50f3\u50e3\u50d3\u50c3\u50b3" + + "\u50a3\u5093\u5083\u5073\u5063\u5053\u5043\u5033\u5023\u5013\u5003" + + "\u4ff3\u4fe3\u4fd3\u4fc3\u4fb3\u4fa3\u4f93\u4f83\u4f73\u4f63\u4f53" + + "\u4f43\u4f33\u4f23\u4f13\u4f03\u4ef3\u4ee3\u4ed3\u4ec3\u4eb3\u4ea3" + + "\u4e93\u4e83\u4e73\u4e63\u4e53\u4e43\u4e33\u4e23\u4e13\u4e03\u4df3" + + "\u4de3\u4dd3\u4dc3\u4db3\u4da3\u4d93\u4d83\u4d73\u4d63\u4d53\u4d43" + + "\u4d33\u4d23\u4d13\u4d03\u4cf3\u4ce3\u4cd3\u4cc3\u4cb3\u4ca3\u4c93" + + "\u4c83\u4c73\u4c63\u4c53\u4c43\u4c33\u4c23\u4c13\u4c03\u4bf3\u4be3" + + "\u4bd3\u4bc3\u4bb3\u4ba3\u4b93\u4b83\u4b73\u4b63\u4b53\u4b43\u4b33" + + "\u4b23\u4b13\u4b03\u4af3\u4ae3\u4ad3\u4ac3\u4ab3\u4aa3\u4a93\u4a83" + + "\u4a73\u4a63\u4a53\u4a43\u4a33\u4a23\u4a13\u4a03\u49f3\u49e3\u49d3" + + "\u49c3\u49b3\u49a3\u4993\u4983\u4973\u4963\u4953\u4943\u4933\u4923" + + "\u4913\u4903\u48f3\u48e3\u48d3\u48c3\u48b3\u48a3\u4893\u4883\u4873" + + "\u4863\u4853\u4843\u4833\u4823\u4813\u4803\u47f3\u47e3\u47d3\u47c3" + + "\u47b3\u47a3\u4793\u4783\u4773\u4763\u4753\u4743\u4733\u4723\u4713" + + "\u4703\u46f3\u46e3\u46d3\u46c3\u46b3\u46a3\u4693\u4683\u4673\u4663" + + "\u4653\u4643\u4633\u4623\u4613\u4603\u45f3\u45e3\u45d3\u45c3\u45b3" + + "\u45a3\u4593\u4583\u4573\u4563\u4553\u4543\u4533\u4523\u4513\u4503" + + "\u44f3\u44e3\u44d3\u44c3\u44b3\u44a3\u4493\u4483\u4473\u4463\u4453" + + "\u4443\u4433\u4423\u4413\u4403\u43f3\u43e3\u43d3\u43c3\u43b3\u43a3" + + "\u4393\u4383\u4373\u4363\u4353\u4343\u4333\u4323\u4313\u4303\u42f3" + + "\u42e3\u42d3\u42c3\u42b3\u42a3\u4293\u4283\u4273\u4263\u4253\u4243" + + "\u4233\u4223\u4213\u4203\u41f3\u41e3\u41d3\u41c3\u41b3\u41a3\u4193" + + "\u4183\u4173\u4163\u4153\u4143\u4133\u4123\u4113\u4103\u40f3\u40e3" + + "\u40d3\u40c3\u40b3\u40a3\u4093\u4083\u4073\u4063\u4053\u4043\u4033" + + "\u4023\u4013\u4003\u3ff3\u3fe3\u3fd3\u3fc3\u3fb3\u3fa3\u3f93\u3f83" + + "\u3f73\u3f63\u3f53\u3f43\u3f33\u3f23\u3f13\u3f03\u3ef3\u3ee3\u3ed3" + + "\u3ec3\u3eb3\u3ea3\u3e93\u3e83\u3e73\u3e63\u3e53\u3e43\u3e33\u3e23" + + "\u3e13\u3e03\u3df3\u3de3\u3dd3\u3dc3\u3db3\u3da3\u3d93\u3d83\u3d73" + + "\u3d63\u3d53\u3d43\u3d33\u3d23\u3d13\u3d03\u3cf3\u3ce3\u3cd3\u3cc3" + + "\u3cb3\u3ca3\u3c93\u3c83\u3c73\u3c63\u3c53\u3c43\u3c33\u3c23\u3c13" + + "\u3c03\u3bf3\u3be3\u3bd3\u3bc3\u3bb3\u3ba3\u3b93\u3b83\u3b73\u3b63" + + "\u3b53\u3b43\u3b33\u3b23\u3b13\u3b03\u3af3\u3ae3\u3ad3\u3ac3\u3ab3" + + "\u3aa3\u3a93\u3a83\u3a73\u3a63\u3a53\u3a43\u3a33\u3a23\u3a13\u3a03" + + "\u39f3\u39e3\u39d3\u39c3\u39b3\u39a3\u3993\u3983\u3973\u3963\u3953" + + "\u3943\u3933\u3923\u3913\u3903\u38f3\u38e3\u38d3\u38c3\u38b3\u38a3" + + "\u3893\u3883\u3873\u3863\u3853\u3843\u3833\u3823\u3813\u3803\u37f3" + + "\u37e3\u37d3\u37c3\u37b3\u37a3\u3793\u3783\u3773\u3763\u3753\u3743" + + "\u3733\u3723\u3713\u3703\u36f3\u36e3\u36d3\u36c3\u36b3\u36a3\u3693" + + "\u3683\u3673\u3663\u3653\u3643\u3633\u3623\u3613\u3603\u35f3\u35e3" + + "\u35d3\u35c3\u35b3\u35a3\u3593\u3583\u3573\u3563\u3553\u3543\u3533" + + "\u3523\u3513\u3503\u34f3\u34e3\u34d3\u34c3\u34b3\u34a3\u3493\u3483" + + "\u3473\u3463\u3453\u3443\u3433\u3423\u3413\u3403\u33f3\u33e3\u33d3" + + "\u33c3\u33b3\u33a3\u3393\u3383\u3373\u3363\u3353\u3343\u3333\u3323" + + "\u3313\u3303\u32f3\u32e3\u32d3\u32c3\u32b3\u32a3\u3293\u3283\u3273" + + "\u3263\u3253\u3243\u3233\u3223\u3213\u3203\u31f3\u31e3\u31d3\u31c3" + + "\u31b3\u31a3\u3193\u3183\u3173\u3163\u3153\u3143\u3133\u3123\u3113" + + "\u3103\u30f3\u30e3\u30d3\u30c3\u30b3\u30a3\u3093\u3083\u3073\u3063" + + "\u3053\u3043\u3033\u3023\u3013\u3003\u2ff3\u2fe3\u2fd3\u2fc3\u2fb3" + + "\u2fa3\u2f93\u2f83\u2f73\u2f63\u2f53\u2f43\u2f33\u2f23\u2f13\u2f03" + + "\u2ef3\u2ee3\u2ed3\u2ec3\u2eb3\u2ea3\u2e93\u2e83\u2e73\u2e63\u2e53" + + "\u2e43\u2e33\u2e23\u2e13\u2e03\u2df3\u2de3\u2dd3\u2dc3\u2db3\u2da3" + + "\u2d93\u2d83\u2d73\u2d63\u2d53\u2d43\u2d33\u2d23\u2d13\u2d03\u2cf3" + + "\u2ce3\u2cd3\u2cc3\u2cb3\u2ca3\u2c93\u2c83\u3247\u2b6c\u2b5c\u2b4c" + + "\u2b3c\u2b2c\u36e2\u36d2\u36c2\u36b2\u36a2\u3692\u3682\u3672\u3662" + + "\u3652\u3642\u3632\u3622\u3612\u3602\u35f2\u35e2\u35d2\u35c2\u35b2" + + "\u35a2\u3592\u3582\u3572\u3562\u3552\u3542\u3532\u3522\u3512\u3502" + + "\u34f2\u34e2\u34d2\u34c2\u34b2\u34a2\u3492\u3482\u3472\u3462\u3452" + + "\u3442\u3432\u3422\u3412\u3402\u33f2\u33e2\u33d2\u33c2\u33b2\u33a2" + + "\u3392\u3382\u3372\u3362\u3352\u3342\u3332\u3322\u3312\u3302\u32f2" + + "\u32e2\u32d2\u32c2\u32b2\u32a2\u3292\u3282\u3272\u3262\u3252\u3242" + + "\u3232\u3222\u3212\u3202\u31f2\u31e2\u31d2\u31c2\u31b2\u31a2\u3192" + + "\u3182\u3172\u3162\u3152\u3142\u3132\u3122\u3112\u3102\u30f2\u30e2" + + "\u30d2\u30c2\u30b2\u30a2\u3092\u3082\u3072\u3062\u3052\u3042\u3032" + + "\u3022\u3012\u3002\u2ff2\u2fe2\u2fd2\u2fc2\u2fb2\u2fa2\u2f92\u2f82" + + "\u2f72\u2f62\u2f52\u2f42\u2f32\u2f22\u2f12\u2f02\u2ef2\u2ef2\u2ee2" + + "\u2ed2\u2ec2\u2eb2\u2ea2\u2e92\u2e82\u2e72\u2e62\u2e52\u2e42\u2e32" + + "\u2e22\u2e12\u2e02\u2df2\u2de2\u2dd2\u2dc2\u2db2\u2da2\u2d92\u2d82" + + "\u2d72\u2d62\u2d52\u2d42\u2d32\u2d22\u2d12\u2d02\u2cf2\u2ce2\u2cd2" + + "\u2cc2\u2cb2\u2ca2\u2c92\u2c82\u2c72\u2c62\u2c52\u2c42\u2c32\u2c22" + + "\u2c12\u2c02\u2bf2\u2be2\u2bd2\u2bc2\u2bb2\u2ba2\u2b92\u2b82\u2b72" + + "\u2b62\u2b52\u2b42\u2b32\u2b22\u2b12\u2b02\u2af2\u2ae2\u2ad2\u2ac2" + + "\u2ab2\u2aa2\u2a92\u2a82\u2a72\u2a62\u2a52\u2a42\u2a32\u2a22\u2a12" + + "\u2a02\u29f2\u29e2\u29d2\u29c2\u29b2\u29a2\u2992\u2982\u2972\u2962" + + "\u2952\u2942\u2932\u2922\u2912\u2902\u28f2\u28e2\u28d2\u28c2\u28b2" + + "\u28a2\u2892\u2882\u2872\u2862\u2852\u2842\u2832\u2822\u2812\u2802" + + "\u27f2\u27e2\u27d2\u27c2\u27b2\u27a2\u2792\u2782\u2772\u2762\u2752" + + "\u2742\u2732\u2722\u2712\u2702\u26f2\u26e2\u26d2\u26c2\u26b2\u26a2" + + "\u2692\u2682\u2672\u2662\u2652\u2642\u2632\u2622\u2612\u2602\u25f2" + + "\u25e2\u25d2\u25c2\u25b2\u25a2\u2592\u2582\u2572\u2562\u2552\u2542" + + "\u2532\u2522\u2512\u2502\u24f2\u24e2\u24d2\u24c2\u24b2\u24a2\u2492" + + "\u2482\u2472\u2462\u2452\u2442\u2432\u2422\u2412\u2402\u23f2\u23e2" + + "\u23d2\u23c2\u23b2\u23a2\u2392\u2382\u2372\u2362\u2352\u2342\u2332" + + "\u2322\u2312\u2302\u22f2\u22e2\u22d2\u22c2\u22b2\u22a2\u2292\u2282" + + "\u2272\u2262\u2252\u2242\u2232\u2222\u2212\u2202\u21f2\u21e2\u21d2" + + "\u21c2\u21b2\u21a2\u2192\u2182\u2172\u2162\u2152\u2142\u2132\u2122" + + "\u2112\u2102\u20f2\u20e2\u20d2\u20c2\u20b2\u20a2\u2092\u2082\u2072" + + "\u2062\u2052\u2042\u2032\u2022\u2012\u2002\u1ff2\u1fe2\u1fd2\u1fc2" + + "\u1fb2\u1fa2\u1f92\u1f82\u1f72\u1f62\u1f52\u1f42\u1f32\u1f22\u1f12" + + "\u1f02\u1ef2\u1ee2\u1ed2\u1ec2\u1eb2\u1ea2\u1e92\u1e82\u1e72\u1e62" + + "\u1e52\u1e42\u1e32\u1e22\u1e12\u1e02\u1df2\u1de2\u1dd2\u1dc2\u1db2" + + "\u1da2\u1d92\u1d82\u1d72\u1d62\u1d52\u1d42\u1d32\u1d22\u1d12\u1d02" + + "\u1cf2\u1ce2\u1cd2\u1cc2\u1cb2\u1ca2\u1c92\u1c82\u1c72\u1c62\u1c52" + + "\u1c42\u1c32\u1c22\u1c12\u1c02\u1bf2\u1be2\u1bd2\u1bc2\u1bb2\u1ba2" + + "\u1b92\u1b82\u1b72\u1b62\u1b52\u1b42\u1b32\u1b22\u1b12\u1b02\u1af2" + + "\u1ae2\u1ad2\u1ac2\u1ab2\u1aa2\u1a92\u1a82\u1a72\u1a62\u1a52\u1a42" + + "\u1a32\u1a22\u1a12\u1a02\u19f2\u19e2\u19d2\u19c2\u19b2\u19a2\u1992" + + "\u1982\u1972\u1962\u1952\u1942\u1932\u1922\u1912\u1902\u18f2\u18e2" + + "\u18d2\u18c2\u18b2\u18a2\u1892\u1882\u1872\u1862\u1852\u1842\u1832" + + "\u1822\u1812\u1802\u17f2\u17e2\u17d2\u17c2\u17b2\u17a2\u1792\u1782" + + "\u1772\u1762\u1752\u1742\u1732\u1722\u1712\u1702\u16f2\u16e2\u16d2" + + "\u16c2\u16b2\u16a2\u1692\u1682\u1672\u1662\u1652\u1642\u1632\u1622" + + "\u1612\u1602\u0b13\u0b03\u0af3\u0ae3\u0ad3\u0ac3\u0ab3\u0aa3\u0a93" + + "\u0a83\u0a73\u0a63\u0a53\u0a43\u0a33\u0a23\u0a13\u0a03\u0dd8\u09e3" + + "\u09d3\u09c3\u0d9b\u08ac\u089c\u088c\u087c\u086c\u085c\u084c\u083c" + + "\u082c\u1402\u0b35\u13f2\u13ec\u0b14\u083f\u082f\u081f\u080f\u07ff" + + "\u07ef\u0b82\u075c\u07bc\u07af\u079f\u078f\u077f\u076f\u075f\u074f" + + "\u073f\u072f\u071f\u070f\u06ff\u06ef\u06df\u06cf\u06bf\u06af\u069f" + + "\u068f\u067f\u066f\u0661\u05dc\u063f\u062f\u061f\u060f\u05fd\u05ef" + + "\u05df\u096c\u054c\u053c\u09a9\u0666\u050c\u0818\u10fc\u10f8\u0e1e" + + "\u10e8\u08b3\u050f\u04ff\u04ef\u04df\u04cf\u04bf\u04af\u087c\u0795" + + "\u0127\u0154\u0154\u017a\u1008\u0859\u08ad\u0493\u0485\u0473\u0453" + + "\u01c3\u038b\u0f88\u0333", + + "\000\uffff?\004\004\u00fd\u00bd}=\ufffd\uffbd" + + "\uff7d\uff7d\ufef2\uff2d\ufe7d\ufc7f\ufc6f\ufe6d\ufd7d\ufd3d\ufcfd" + + "\ufcbd\ufc7d\ufc3d\ufbfd\ufbbd\ufb7d\ufb3d\ufafd\ufabd\ufa7d\ufb2d" + + "\uf9fd\uf9bd\uf97d\uf93d\uf8fd\uf8bd\uf87d\uf83d\uf7fd\uf7bd\uf77d" + + "\uf73d\uf6fd\uf6bd\uf67d\uf63d\uf5fd\uf5bd\uf57d\uf53d\uf4fd\uf4bd" + + "\uf47d\uf43d\uf3fd\uf3bd\uf37d\uf33d\uf2fd\uf2bd\uf27d\uf23d\uf1fd" + + "\uf1bd\uf17d\uf13d\uf0fd\uf0bd\uf07d\uf03d\ueffd\uefbd\uef7d\uef3d" + + "\ueefd\ueebd\uee7d\uee3d\uedfd\uedbd\ued7d\ued3d\uecfd\uecbd\uec7d" + + "\uec3d\uebfd\uebbd\ueb7d\ueb3d\ueafd\ueabd\uea7d\uea3d\ue9fd\ue9bd" + + "\ue97d\ue93d\ue8fd\ue8bd\ue87d\ue83d\ue7fd\ue7bd\ue77d\ue73d\ue6fd" + + "\ue6bd\ue67d\ue63d\ue5fd\ue5bd\ue57d\ue53d\ue4fd\ue4bd\ue47d\ue43d" + + "\ue3fd\ue3bd\ue37d\ue33d\ue2fd\ue2bd\ue27d\ue23d\ue1fd\ue1bd\ue17d" + + "\ue13d\ue0fd\ue0bd\ue07d\ue03d\udffd\udfbd\udf7d\udf3d\udefd\udebd" + + "\ude7d\ude3d\uddfd\uddbd\udd7d\udd3d\udcfd\udcbd\udc7d\udc3d\udbfd" + + "\udbbd\udb7d\udb3d\udafd\udabd\uda7d\uda3d\ud9fd\ud9bd\ud97d\ud93d" + + "\ud8fd\ud8bd\ud87d\ud83d\ud7fd\ud7bd\ud77d\ud73d\ud6fd\ud6bd\ud67d" + + "\ud63d\ud5fd\ud5bd\ud57d\ud53d\ud4fd\ud4bd\ud47d\ud43d\ud3fd\ud3bd" + + "\ud37d\ud33d\ud2fd\ud2bd\ud27d\ud23d\ud1fd\ud1bd\ud17d\ud13d\ud0fd" + + "\ud0bd\ud07d\ud03d\ucffd\ucfbd\ucf7d\ucf3d\ucefd\ucebd\uce7d\uce3d" + + "\ucdfd\ucdbd\ucd7d\ucd3d\uccfd\uccbd\ucc7d\ucc3d\ucbfd\ucbbd\ucb7d" + + "\ucb3d\ucafd\ucabd\uca7d\uca3d\uc9fd\uc9bd\uc97d\uc93d\uc8fd\uc8bd" + + "\uc87d\uc83d\uc7fd\uc7bd\uc77d\uc73d\uc6fd\uc6bd\uc67d\uc63d\uc5fd" + + "\uc5bd\uc57d\uc53d\uc4fd\uc4bd\uc47d\uc43d\uc3fd\uc3bd\uc37d\uc33d" + + "\uc2fd\uc2bd\uc27d\uc23d\uc1fd\uc1bd\uc17d\uc13d\uc0fd\uc0bd\uc07d" + + "\uc03d\ubffd\ubfbd\ubf7d\ubf3d\ubefd\ubebd\ube7d\ube3d\ubdfd\ubdbd" + + "\ubd7d\ubd3d\ubcfd\ubcbd\ubc7d\ubc3d\ubbfd\ubbbd\ubb7d\ubb3d\ubafd" + + "\ubabd\uba7d\uba3d\ub9fd\ub9bd\ub97d\ub93d\ub8fd\ub8bd\ub87d\ub83d" + + "\ub7fd\ub7bd\ub77d\ub73d\ub6fd\ub6bd\ub67d\ub63d\ub5fd\ub5bd\ub57d" + + "\ub53d\ub4fd\ub4bd\ub47d\ub43d\ub3fd\ub3bd\ub37d\ub33d\ub2fd\ub2bd" + + "\ub27d\ub23d\ub1fd\ub1bd\ub17d\ub13d\ub0fd\ub0bd\ub07d\ub03d\uaffd" + + "\uafbd\uaf7d\uaf3d\uaefd\uaebd\uae7d\uae3d\uadfd\uadbd\uad7d\uad3d" + + "\uacfd\uacbd\uac7d\uac3d\uabfd\uabbd\uab7d\uab3d\uaafd\uaabd\uaa7d" + + "\uaa3d\ua9fd\ua9bd\ua97d\ua93d\ua8fd\ua8bd\ua87d\ua83d\ua7fd\ua7bd" + + "\ua77d\ua73d\ua6fd\ua6bd\ua67d\ua63d\ua5fd\ua5bd\ua57d\ua53d\ua4fd" + + "\ua4bd\ua47d\ua43d\ua3fd\ua3bd\ua37d\ua33d\ua2fd\ua2bd\ua27d\ua23d" + + "\ua1fd\ua1bd\ua17d\ua13d\ua0fd\ua0bd\ua07d\ua03d\u9ffd\u9fbd\u9f7d" + + "\u9f3d\u9efd\u9ebd\u9e7d\u9e3d\u9dfd\u9dbd\u9d7d\u9d3d\u9cfd\u9cbd" + + "\u9c7d\u9c3d\u9bfd\u9bbd\u9b7d\u9b3d\u9afd\u9abd\u9a7d\u9a3d\u99fd" + + "\u99bd\u997d\u993d\u98fd\u98bd\u987d\u983d\u97fd\u97bd\u977d\u973d" + + "\u96fd\u96bd\u967d\u963d\u95fd\u95bd\u957d\u953d\u94fd\u94bd\u947d" + + "\u943d\u93fd\u93bd\u937d\u933d\u92fd\u92bd\u927d\u923d\u91fd\u91bd" + + "\u917d\u913d\u90fd\u90bd\u907d\u903d\u8ffd\u8fbd\u8f7d\u8f3d\u8efd" + + "\u8ebd\u8e7d\u8e3d\u8dfd\u8dbd\u8d7d\u8d3d\u8cfd\u8cbd\u8c7d\u8c3d" + + "\u8bfd\u8bbd\u8b7d\u8b3d\u8afd\u8abd\u8a7d\u8a3d\u89fd\u89bd\u897d" + + "\u893d\u88fd\u88bd\u887d\u883d\u87fd\u87bd\u877d\u873d\u86fd\u86bd" + + "\u867d\u863d\u85fd\u85bd\u857d\u853d\u84fd\u84bd\u847d\u843d\u83fd" + + "\u83bd\u837d\u833d\u82fd\u82bd\u827d\u823d\u81fd\u81bd\u817d\u813d" + + "\u80fd\u80bd\u807d\u803d\u7ffd\u7fbd\u7f7d\u7f3d\u7efd\u7ebd\u7e7d" + + "\u7e3d\u7dfd\u7dbd\u7d7d\u7d3d\u7cfd\u7cbd\u7c7d\u7c3d\u7bfd\u7bbd" + + "\u7b7d\u7b3d\u7afd\u7abd\u7a7d\u7a3d\u79fd\u79bd\u797d\u793d\u78fd" + + "\u78bd\u787d\u783d\u77fd\u77bd\u777d\u773d\u76fd\u76bd\u767d\u763d" + + "\u75fd\u75bd\u757d\u753d\u74fd\u74bd\u747d\u743d\u73fd\u73bd\u737d" + + "\u733d\u72fd\u72bd\u727d\u723d\u71fd\u71bd\u717d\u713d\u70fd\u70bd" + + "\u707d\u703d\u6ffd\u6fbd\u6f7d\u6f3d\u6efd\u6ebd\u6e7d\u6e3d\u6dfd" + + "\u6dbd\u6d7d\u6d3d\u6cfd\u6cbd\u6c7d\u6c3d\u6bfd\u6bbd\u6b7d\u6b3d" + + "\u6afd\u6abd\u6a7d\u6a3d\u69fd\u69bd\u697d\u693d\u68fd\u68bd\u687d" + + "\u683d\u67fd\u67bd\u677d\u673d\u66fd\u66bd\u667d\u663d\u65fd\u65bd" + + "\u657d\u653d\u64fd\u64bd\u647d\u643d\u63fd\u63bd\u637d\u633d\u62fd" + + "\u62bd\u627d\u623d\u61fd\u61bd\u617d\u613d\u60fd\u60bd\u607d\u603d" + + "\u5ffd\u5fbd\u5f7d\u5f3d\u5efd\u5ebd\u5e7d\u5e3d\u5dfd\u5dbd\u5d7d" + + "\u5d3d\u5cfd\u5cbd\u5c7d\u5c3d\u5bfd\u5bbd\u5b7d\u5b3d\u5afd\u5abd" + + "\u5a7d\u5a3d\u59fd\u59bd\u597d\u593d\u58fd\u58bd\u587d\u583d\u57fd" + + "\u57bd\u577d\u573d\u56fd\u56bd\u567d\u563d\u55fd\u55bd\u557d\u553d" + + "\u54fd\u54bd\u547d\u543d\u53fd\u53bd\u537d\u533d\u52fd\u52bd\u527d" + + "\u523d\u51fd\u51bd\u517d\u513d\u50fd\u50bd\u507d\u503d\u4ffd\u4fbd" + + "\u4f7d\u4f3d\u4efd\u4ebd\u4e7d\u4e3d\u4dfd\u4dbd\u4d7d\u4d3d\u4cfd" + + "\u4cbd\u4c7d\u4c3d\u4bfd\u4bbd\u4b7d\u4b3d\u4afd\u4abd\u4a7d\u4a3d" + + "\u49fd\u49bd\u497d\u493d\u48fd\u48bd\u487d\u483d\u47fd\u47bd\u477d" + + "\u473d\u46fd\u46bd\u467d\u463d\u45fd\u45bd\u457d\u453d\u44fd\u44bd" + + "\u447d\u443d\u43fd\u43bd\u437d\u433d\u42fd\u42bd\u427d\u423d\u41fd" + + "\u41bd\u417d\u413d\u40fd\u40bd\u407d\u403d\u3ffd\u3fbd\u3f7d\u3f3d" + + "\u3efd\u3ebd\u3e7d\u3e3d\u3dfd\u3dbd\u3d7d\u3d3d\u3cfd\u3cbd\u3c7d" + + "\u3c3d\u3bfd\u3bbd\u3b7d\u3b3d\u3afd\u3abd\u3a7d\u3a3d\u39fd\u39bd" + + "\u397d\u393d\u38fd\u38bd\u387d\u383d\u37fd\u37bd\u377d\u373d\u36fd" + + "\u36bd\u367d\u363d\u35fd\u35bd\u357d\u353d\u34fd\u34bd\u347d\u343d" + + "\u33fd\u33bd\u337d\u333d\u32fd\u32bd\u327d\u31d0\u3190\u3150\u311a" + + "\u30a6\u2ffb\u2ff8\u3032\u303d\u2ffd\u2fbd\u2f7d\u306d\u3056\u2ebd" + + "\u2e7d\u3034\u306a\u30a3\u2f64\u3060\u2fa5\u2ec8\u2e94\u2e2c\u2df8" + + "\u2df8\u2d16\u2cdc\u2ca2\u2c68\u2de0\u2a3d\u29fd\u29bd\u297d\u293d" + + "\u28fd\u28bd\u287d\u283d\u27fd\u27bd\u277d\u273d\u26fd\u26bd\u267d" + + "\u263d\u25fd\u25bd\u257d\u253d\u24fd\u24bd\u247d\u243d\u23fd\u23bd" + + "\u237d\u233d\u22fd\u22bd\u227d\u223d\u21fd\u21bd\u217d\u213d\u20fd" + + "\u20bd\u207d\u203d\u1ffd\u1fbd\u1f7d\u1f3d\u1efd\u1ebd\u1e7d\u1e3d" + + "\u1dfd\u1dbd\u1d7d\u1d3d\u1cfd\u1cbd\u1c7d\u1c3d\u1bfd\u1bbd\u1b7d" + + "\u1b3d\u1afd\u1abd\u1a7d\u1a3d\u19fd\u19bd\u197d\u193d\u18fd\u18bd" + + "\u187d\u183d\u17fd\u17bd\u177d\u173d\u16fd\u16bd\u167d\u163d\u15fd" + + "\u15bd\u157d\u153d\u14fd\u14bd\u147d\u143d\u13fd\u13bd\u137d\u133d" + + "\u12fd\u12bd\u127d\u123d\u11fd\u11bd\u117d\u113d\u10fd\u10bd\u107d" + + "\u103d\u0ffd\u0fbd\u0f7d\u0f3d\u0efd\u0ebd\u0e7d\u0e3d\u0dfd\u0dbd" + + "\u0d7d\u0d3d\u0cfd\u0cbd\u0c7d\u0c3d\u0bfd\u0bbd\u0b7d\u0b3d\u0afd" + + "\u0abd\u0a7d\u0a3d\u09fd\u09bd\u097d\u093d\u08fd\u08bd\u087d\u083d" + + "\u07fd\u07bd\u077d\u073d\u06fd\u06bd\u067d\u063d\u05fd\u05bd\u057d" + + "\u053d\u04fd\u04bd\u047d\u043d\u03fd\u03bd\u037d\u033d\u02fd\u02bd" + + "\u027d", + + "\000\uff80\uff00\ufe80\ufe00\ufd80\ufd00\ufc80\ufc00\ufb80\ufb00" + + "\ufa80\ufa00\uf980\uf900\uf880\uf800\uf780\uf700\uf680\uf600\uf580" + + "\uf500\uf480\uf400\uf380\uf300\uf280\uf200\uf180\uf100\uf080\uf000" + + "\uef80\uef00\uee80\uee00\ued80\ued00\uec80\uec00\ueb80\ueb00\uea80" + + "\uea00\ue980\ue900\ue880\ue800\ue780\ue700\ue680\ue600\ue580\ue500" + + "\ue480\ue400\ue380\ue300\ue280\ue200\ue180\ue100\ue080\ue000\udf80" + + "\udf00\ude80\ude00\udd80\udd00\udc80\udc00\udb80\udb00\uda80\uda00" + + "\ud980\ud900\ud880\ud800\ud780\ud700\ud680\ud600\ud580\ud500\ud480" + + "\ud400\ud380\ud300\ud280\ud200\ud180\ud100\ud080\ud000\ucf80\ucf00" + + "\uce80\uce00\ucd80\ucd00\ucc80\ucc00\ucb80\ucb00\uca80\uca00\uc980" + + "\uc900\uc880\uc800\uc780\uc700\uc680\uc600\uc580\uc500\uc480\uc400" + + "\uc380\uc300\uc280\uc200\uc180\uc100\uc080\uc000\ubf80\ubf00\ube80" + + "\ube00\ubd80\ubd00\ubc80\ubc00\ubb80\ubb00\uba80\uba00\ub980\ub900" + + "\ub880\ub800\ub780\ub700\ub680\ub600\ub580\ub500\ub480\ub400\ub380" + + "\ub300\ub280\ub200\ub180\ub100\ub080\ub000\uaf80\uaf00\uae80\uae00" + + "\uad80\uad00\uac80\uac00\uab80\uab00\uaa80\uaa00\ua980\ua900\ua880" + + "\ua800\ua780\ua700\ua680\ua600\ua580\ua500\ua480\ua400\ua380\ua300" + + "\ua280\ua200\ua180\ua100\ua080\ua000\u9f80\u9f00\u9e80\u9e00\u9d80" + + "\u9d00\u9c80\u9c00\u9b80\u9b00\u9a80\u9a00\u9980\u9900\u9880\u9800" + + "\u9780\u9700\u9680\u9600\u9580\u9500\u9480\u9400\u9380\u9300\u9280" + + "\u9200\u9180\u9100\u9080\u9000\u8f80\u8f00\u8e80\u8e00\u8d80\u8d00" + + "\u8c80\u8c00\u8b80\u8b00\u8a80\u8a00\u8980\u8900\u8880\u8800\u8780" + + "\u8700\u8680\u8600\u8580\u8500\u8480\u8400\u8380\u8300\u8280\u8200" + + "\u8180\u8100\u8080\u8000\u7f80\u7f00\u7e80\u7e00\u7d80\u7d00\u7c80" + + "\u7c00\u7b80\u7b00\u7a80\u7a00\u7980\u7900\u7880\u7800\u7780\u7700" + + "\u7680\u7600\u7580\u7500\u7480\u7400\u7380\u7300\u7280\u7200\u7180" + + "\u7100\u7080\u7000\u6f80\u6f00\u6e80\u6e00\u6d80\u6d00\u6c80\u6c00" + + "\u6b80\u6b00\u6a80\u6a00\u6980\u6900\u6880\u6800\u6780\u6700\u6680" + + "\u6600\u6580\u6500\u6480\u6400\u6380\u6300\u6280\u6200\u6180\u6100" + + "\u6080\u6000\u5f80\u5f00\u5e80\u5e00\u5d80\u5d00\u5c80\u5c00\u5b80" + + "\u5b00\u5a80\u5a00\u59a9\u5980\u5900\u5880\u5800\u5780\u5700\u5680" + + "\u5600\u5580\u5500\u5480\u5400\u5380\u5300\u5280\u5200\u5180\u5100" + + "\u5080\u5000\u4f80\u4f00\u4e80\u4e00\u4d80\u4d00\u4c80\u4c00\u4b80" + + "\u4b00\u4a80\u4a00\u4980\u4900\u4880\u4800\u4780\u4700\u4680\u4600" + + "\u4580\u4500\u4480\u4400\u4380\u4300\u4280\u4200\u4180\u4100\u4080" + + "\u4000\u3f80\u3f00\u3e80\u3e00\u3d80\u3d00\u3c80\u3c00\u3b80\u3b00" + + "\u3a80\u3a00\u3980\u3900\u3880\u3800\u3780\u3700\u3680\u3600\u3580" + + "\u3500\u3480\u3400\u3380\u3300\u3280\u3200\u3180\u3100\u3080\u3000" + + "\u2f80\u2f00\u2e80\u2e00\u2d80\u2d00\u2c80\u2c00\u2b80\u2b00\u2a80" + + "\u2a00\u2980\u2900\u2880\u2800\u2780\u2700\u2680\u2600\u2580\u2500" + + "\u2480\u2400\u2380\u2300\u2280\u2200\u2180\u2100\u2080\u2000\u1f80" + + "\u1f00\u1e80\u1e00\u1d80\u1d00\u1c80\u1c00\u1b80\u1b00\u1a80\u1a00" + + "\u1980\u1900\u1880\u1800\u1780\u1700\u1680\u1600\u1580\u1500\u1480" + + "\u1400\u1380\u1300\u1280\u1200\u1180\u1100\u1080\u1000\u0f80\u0f00" + + "\u0e80\u0e00\u0d80\u0d00\u0c80\u0c00\u0b80\u0b00\u0a80\u0a00\u0980" + + "\u0900\u0800\u0780\u0700\u0680\u0662\u0600\u0580\u0500\u0480\u0400" + + "\u0380\u0300\u0280\u0200\u0180\u0100", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "\u00ff\000\uff00\ufe90\ufe80\ufe00\ufd80\ufd00\ufc80\ufc00\ufb80" + + "\ufb00\ufa80\ufa00\uf980\uf900\uf880\uf800\uf780\uf700\uf680\uf600" + + "\uf580\uf500\uf480\uf400\uf380\uf300\uf280\uf200\uf180\uf100\uf080" + + "\uf000\uef80\uef00\uee80\uee00\ued80\ued00\uec80\uec00\ueb80\ueb00" + + "\uea80\uea00\ue980\ue900\ue880\ue800\ue780\ue700\ue680\ue600\ue580" + + "\ue500\ue480\ue400\ue380\ue300\ue280\ue200\ue180\ue100\ue080\ue000" + + "\udf80\udf00\ude80\ude00\udd80\udd00\udc80\udc00\udb80\udb00\uda80" + + "\uda00\ud980\ud900\ud880\ud800\ud780\ud700\ud680\ud600\ud580\ud500" + + "\ud480\ud400\ud380\ud300\ud280\ud200\ud180\ud100\ud080\ud000\ucf80" + + "\ucf00\uce80\uce00\ucd80\ucd00\ucc80\ucc00\ucb80\ucb00\uca80\uca00" + + "\uc980\uc900\uc880\uc800\uc780\uc700\uc680\uc600\uc580\uc500\uc480" + + "\uc400\uc380\uc300\uc280\uc200\uc180\uc100\uc080\uc000\ubf80\ubf00" + + "\ube80\ube00\ubd80\ubd00\ubc80\ubc00\ubb80\ubb00\uba80\uba00\ub980" + + "\ub900\ub880\ub800\ub780\ub700\ub680\ub600\ub580\ub500\ub480\ub400" + + "\ub380\ub300\ub280\ub200\ub180\ub100\ub080\ub000\uaf80\uaf00\uae80" + + "\uae00\uad80\uad00\uac80\uac00\uab80\uab00\uaa80\uaa00\ua980\ua900" + + "\ua880\ua800\ua780\ua700\ua680\ua600\ua580\ua500\ua480\ua400\ua380" + + "\ua300\ua280\ua200\ua180\ua100\ua080\ua000\u9f80\u9f00\u9e80\u9e00" + + "\u9d80\u9d00\u9c80\u9c00\u9b80\u9b00\u9a80\u9a00\u9980\u9900\u9880" + + "\u9800\u9780\u9700\u9680\u9600\u9580\u9500\u9480\u9400\u9380\u9300" + + "\u9280\u9200\u9180\u9100\u9080\u9000\u8f80\u8f00\u8e80\u8e00\u8d80" + + "\u8d00\u8c80\u8c00\u8b80\u8b00\u8a80\u8a00\u8980\u8900\u8880\u8800" + + "\u8780\u8700\u8680\u8600\u8580\u8500\u8480\u8400\u8380\u8300\u8280" + + "\u8200\u8180\u8100\u8080\u8000\u7f80\u7f00\u7e80\u7e00\u7d80\u7d00" + + "\u7c80\u7c00\u7b80\u7b00\u7a80\u7a00\u7980\u7900\u7880\u7800\u7780" + + "\u7700\u7680\u7600\u7580\u7500\u7480\u7400\u7380\u7300\u7280\u7200" + + "\u7180\u7100\u7080\u7000\u6f80\u6f00\u6e80\u6e00\u6d80\u6d00\u6c80" + + "\u6c00\u6b80\u6b00\u6a80\u6a00\u6980\u6900\u6880\u6800\u6780\u6700" + + "\u6680\u6600\u6580\u6500\u6480\u6400\u6380\u6300\u6280\u6200\u6180" + + "\u6100\u6080\u6000\u5f80\u5f00\u5e80\u5e00\u5d80\u5d00\u5c80\u5c00" + + "\u5b80\u5b00\u5a80\u5a00\u5980\u5900\u5880\u5800\u5780\u5700\u5680" + + "\u5600\u5580\u5500\u5480\u5400\u5380\u5300\u5280\u5200\u5180\u5100" + + "\u5080\u5000\u4f80\u4f00\u4e80\u4e00\u4d80\u4d00\u4c80\u4c00\u4b80" + + "\u4b00\u4a80\u4a00\u4980\u4900\u4880\u4800\u4780\u4700\u4680\u4600" + + "\u4580\u4500\u4480\u4400\u4380\u4300\u4280\u4200\u4180\u4100\u4080" + + "\u4000\u3f80\u3f00\u3e80\u3e00\u3d80\u3d00\u3c80\u3c00\u3b80\u3b00" + + "\u3a80\u3a00\u3980\u3900\u3880\u3800\u3780\u3700\u3680\u3600\u3580" + + "\u3500\u3480\u3400\u3380\u3300\u3280\u3200\u3180\u3100\u3080\u3000" + + "\u2f80\u2f00\u2e80\u2e00\u2d80\u2d00\u2c80\u2c00\u2b80\u2b00\u2a80" + + "\u2a00\u2980\u2900\u2880\u2800\u2780\u2700\u2680\u2600\u2580\u2500" + + "\u2480\u2400\u2380\u2300\u2280\u2200\u2180\u2100\u2080\u2000\u1f80" + + "\u1f00\u1e80\u1e00\u1d80\u1d00\u1c80\u1c00\u1b80\u1b00\u1a80\u1a00" + + "\u1980\u1900\u1880\u1800\u1780\u1700\u1680\u1600\u1580\u1500\u1480" + + "\u1400\u1380\u1300\u1280\u1200\u1180\u1100\u1080\u1000\u0f80\u0f00" + + "\u0e80\u0e00\u0d80\u0d00\u0c80\u0c00\u0b80\u0b00\u0a80\u0a00\u0980" + + "\u0900\u0880\u0800\u0780\u0700\u0680\u0600\u0580\u0500\u0480\u0400" + + "\u0380\u0300\u0280\u0200\u0180\u0100", + + "", + + ""}; + + /** + * The array containing the numeric values that are too large to be stored as + * chars in NUM_VALUE. NUM_VALUE in this case will contain a negative integer + * N such that LARGENUMS[-N - 3] contains the correct numeric value. + */ + int[] LARGENUMS + = new int[] {40000, 50000, 60000, 70000, 80000, 90000}; + + /** + * Information about each character. The low order 5 bits form the + * character type, the next bit is a flag for non-breaking spaces, and the + * next bit is a flag for mirrored directionality. The high order 9 bits + * form the offset into the attribute tables. Note that this limits the + * number of unique character attributes to 512, which is not a problem + * as of Unicode version 4.0.0, but may soon become one. + */ + String[] DATA = new String[]{ + "\u2282\u2302\u2382\u2402\u2482\u2502\u2582\u2602\u2682\u2702\u2782" + + "\u0455\u0c99\u04d6\u0c99\017\017\017\017\017\017\017" + + "\017\017\u008f\u010f\u008f\u018f\u010f\017\017\017\017" + + "\017\u010f\017\017\017\017\017\017\017\017\017" + + "\017\017\017\017\017\017\017\u010f\u010f\u010f\u008f" + + "\u0709\u0789\u0809\u0889\u0909\u0989\u0a09\u0a89\u0b09\u0b89\u0598" + + "\u0298\u0c59\u0c99\u0c59\u0298\u0298\u0c99\u0298\u1a97\u3f80\u3f80" + + "\u0298\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u020c\u0298\u0298" + + "\u0318\u039a\u0318\u0298\u0298\u0455\u04d6\u0298\u0519\u0598\u0614" + + "\u0598\u0698\u2a9c\u0519\u2b0b\u2b8b\u1a1b\u2c02\u289c\u0298\u1a1b" + + "\u2c8b\u2902\u2d5e\u2d8b\u2d8b\u2d8b\u0298\u0d01\u0d81\u0e01\u0e81" + + "\u0f01\u0f81\u1001\u1081\u1101\u1181\u1201\u1281\u1301\u1381\u1401" + + "\u1481\u1501\u1581\u1601\u1681\u1701\u1781\u1801\u1881\u1901\u1981" + + "\u0455\u0298\u04d6\u1a1b\u1a97\u0298\u0298\u0298\u0c99\u0455\u04d6" + + "\u0298\u0298\u0298\u0298\u0298\u0298\u0298\u0298\u0298\u858d\u860e" + + "\u8690\u8710\u8790\u8810\u8890\u82ac\u282c\u0298\u039a\u039a\u039a" + + "\u039a\u289c\u289c\u1a1b\u289c\u2902\u29dd\u0c99\u2a10\u289c\u1a1b" + + "\u1b02\u1b82\u1c02\u1c82\u1d02\u1d82\u1e02\u1e82\u1f02\u1f82\u2002" + + "\u2082\u2102\u2182\u2202\u4a82\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01" + + "\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u0c99" + + "\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e82\u3c01\u3c83\u3d02" + + "\u3001\u3082\u3e01\u3e81\u3001\u3082\u3001\u3082\u3001\u3082\u3001" + + "\u3082\u3201\u3001\u3082\u3001\u3082\u3001\u3082\u3282\u4a82\u2f02" + + "\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02" + + "\u2f02\u2f02\u2f02\u2f02\u0c99\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02" + + "\u2f02\u2f82\u3f01\u2902\u3001\u3082\u3001\u3082\u3001\u3082\u3001" + + "\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3d82\u3001" + + "\u3082\u539c\u4786\u4786\u4786\u4786\u3f80\u5407\u5407\u3001\u3082" + + "\u3001\u3082\u3001\u3082\u3f80\u3f80\u3001\u3082\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u4786\u6008\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05" + + "\u3f80\u3b05\u3f80\u3f80\u3b05\u3b05\u3f80\u3b05\u3f80\u3f80\u3b05" + + "\u3f80\u3f80\u2e82\u7e02\u2e82\u3f80\u2e82\u4a82\u8181\u8181\u8201" + + "\u8201\u7f03\u1a1b\u1a1b\u3f80\u4786\u4786\u6008\u3f80\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3b05\u3f80\u3b05" + + "\u3b05\u3b05\u3b05\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3f80\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80" + + "\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u5518\u5518\u3b05\u3b05\u3b05\u3b05\u3c01\u3c83" + + "\u3d02\u3c01\u3c83\u3d02\u3c01\u3c83\u3d02\u3001\u3082\u3001\u3082" + + "\u2902\u2902\u2902\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3b05\u3b05\u3b05\u3b05\u3f80\u3b05\u3f80\u3b05\u3b05\u3f80" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u4786\u3b05\u6008\u6008" + + "\u4786\u4786\u4786\u3f80\u3f80\u3f80\u6008\u6008\u3f80\u3f80\u6008" + + "\u6008\u4786\u3f80\u3f80\u3101\u3182\u3001\u3082\u3001\u3082\u3001" + + "\u3082\u2902\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u2e82" + + "\u2e82\u2e82\u2e82\u2e82\u7882\u3f80\u3f80\u3f80\u3f80\u1a1b\u1a1b" + + "\u3f80\u3f80\u3f80\u3f80\u4684\u3f80\u3f80\u3f80\u0298\u3f80\u5481" + + "\u5481\u5481\u5481\u5481\u5481\u5481\u5481\u5481\u5481\u5481\u5481" + + "\u5481\u5481\u5481\u5481\u3f80\u3f80\u4684\u5518\u5518\u5518\u5518" + + "\u5518\u5518\u539c\u539c\u539c\u539c\u539c\u4786\u4786\u539c\u539c" + + "\u539c\u539c\u539c\u539c\u4786\u539c\u539c\u539c\u539c\u539c\u539c" + + "\u3f80\u3f80\u539c\u3b05\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u4d82\u4e02\u4e81" + + "\u4e81\u4e81\u4f02\u4f82\u2902\u3001\u3082\u3001\u3082\u3001\u3082" + + "\u3001\u3082\u3001\u3082\u2e82\u3001\u3082\u3001\u3082\u3001\u3082" + + "\u3981\u3001\u3082\u3981\u2902\u2902\u3001\u3082\u3981\u3001\u4502" + + "\u2902\u2902\u4502\u2902\u2902\u2902\u2902\u4502\u2902\u4582\u4582" + + "\u2902\u2902\u2902\u2902\u4402\u2902\u2902\u4482\u2902\u2902\u2902" + + "\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u4002\u4082\u2902\u4102" + + "\u4102\u2902\u4182\u2902\u4202\u2902\u2902\u2902\u2902\u3301\u3001" + + "\u3082\u3001\u3082\u3381\u3001\u3082\u3401\u3401\u3001\u3082\u2902" + + "\u3481\u3501\u3581\u3001\u3082\u3401\u3601\u3682\u3701\u3781\u3001" + + "\u3082\u2902\u2902\u3701\u3801\u3882\u3901\u3082\u3a01\u3a01\u3001" + + "\u3082\u3001\u3082\u3a81\u3001\u3082\u2902\u3b05\u3001\u3082\u2902" + + "\u3b82\u4786\u4786\u4786\u4786\u4786\u4806\u4786\u4786\u4786\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u3f80\u4786\u4786\u4786\u5698" + + "\u4786\u4786\u5698\u4786\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u6008\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05" + + "\u3f80\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80\u3b05\u3b05\u3f80" + + "\u3b05\u3f80\u3b05\u3b05\u3f80\u3b05\u3b05\u3f80\u3b05\u3b05\u3f80" + + "\u3f80\u4786\u3f80\u6008\u6008\u6008\u3f80\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3f80\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80" + + "\u3f80\u6008\u6008\u5518\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u5f90\u5f90" + + "\u5f90\u289c\u289c\u3f80\u3f80\u3f80\u0298\u0298\u6089\u6109\u6189" + + "\u6209\u6289\u6309\u6389\u6409\u6489\u6509\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u4786\u3b05\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3f80\u3f80\u3f80\u3b05\u3b05\u3f80\u3f80\u3f80\u3b05\u3b05\u3b05" + + "\u3f80\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80" + + "\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80\u5582\u5582\u5582\u5582\u5582" + + "\u5582\u5582\u5582\u5582\u5582\u5582\u5582\u5582\u5582\u5582\u5582" + + "\u2e82\u3f80\u5518\u5614\u3f80\u3f80\u3f80\u3f80\u3f80\u4786\u4786" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u5885\u5885" + + "\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885" + + "\u5885\u5885\u5885\u6b95\u6c16\u4102\u2902\u2902\u4282\u2902\u2902" + + "\u2902\u2902\u4302\u4382\u2902\u2902\u2902\u2902\u2902\u4382\u5790" + + "\u5790\u5790\u5790\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u0598\u5818\u289c\u289c\u4e81\u289c\u289c\u289c\u289c\u4e81\u289c" + + "\u289c\u2902\u4e81\u4e81\u4e81\u2902\u2902\u4602\u2902\u2902\u2902" + + "\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u2902\u2902" + + "\u2902\u2902\u4684\u4684\u4684\u4684\u4684\u4684\u4684\u4684\u4684" + + "\u4684\u4684\u4684\u4684\u4684\u4684\u4684\u4704\u4704\u4684\u4684" + + "\u4684\u4684\u4684\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b" + + "\u1a1b\u4684\u1a1b\u5614\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u4684\u4684\u1a1b\u1a1b\u1a1b\u1a1b\u4704\u4704" + + "\u4704\u4704\u4704\u4704\u4704\u4704\u4704\u4704\u4684\u4684\u1a1b" + + "\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b\u1a1b" + + "\u1a1b\u1a1b\u1a1b\u1a1b\u2e82\u7e02\u2e82\u3f80\u2e82\u4a82\u8001" + + "\u8001\u8001\u8001\u7f03\u1a1b\u1a1b\u1a1b\u289c\uac8a\uad0a\uad8a" + + "\uae0a\uae8a\uaf0a\uaf8a\ub00a\ub08a\u4786\u4786\u4786\u4786\u4786" + + "\u4786\u4786\u4786\u3f80\u4786\u4786\u4786\u4786\u4786\u4786\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u3f80\u539c" + + "\u539c\u658b\u660b\u668b\u670b\u539c\u539c\u539c\u539c\u539c\u539c" + + "\u539c\u539c\u539c\u539c\u539c\u289c\u0c99\u289c\u289c\u289c\u289c" + + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u3f80\u289c\u3f80" + + "\u289c\u289c\u289c\u289c\u3f80\u289c\u289c\u289c\u289c\u3f80\u3f80" + + "\u289c\u289c\u289c\u289c\u289c\u539c\u289c\u289c\u289c\u289c\u289c" + + "\u0c99\u0c99\u0c99\u0c99\u0c99\u6b95\u6c16\u0298\u289c\u289c\u289c" + + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u3f80\u289c\u289c\u289c" + + "\u289c\u289c\u289c\u289c\u0455\u04d6\u0455\u04d6\u0455\u04d6\u0455" + + "\u04d6\u738b\u740b\u748b\u750b\u758b\u760b\u768b\u770b\u778b\uab8b" + + "\u738b\u740b\u748b\u750b\u758b\u760b\u4786\u4786\u4786\u4786\u4786" + + "\u4786\u4786\u4786\u3f80\u3f80\u3f80\u3f80\u3f80\u4786\u4786\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786" + + "\u6008\u6008\u3f80\u3f80\u3f80\u6008\u6008\u6008\u3f80\u6008\u6008" + + "\u6008\u4786\u3f80\u3f80\u4786\u6008\u6008\u3f80\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u3b05\u3b05\u3b05\u3f80" + + "\u3b05\u3f80\u3b05\u3f80\u3f80\u3b05\u3b05\u3f80\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3f80\u3b05\u3b05\u3f80\u6008\u4786\u4786\u4786\u4786" + + "\u3f80\u3f80\u6008\u6008\u3f80\u3f80\u6008\u6008\u4786\u3f80\u3f80" + + "\u5002\u5082\u5102\u2902\u5181\u5202\u0c99\u3001\u3082\u5281\u3001" + + "\u3082\u3f80\u3f80\u3f80\u3f80\u1a1b\u1a1b\u4881\u0298\u4901\u4901" + + "\u4901\u3f80\u4981\u3f80\u4a01\u4a01\u2e01\u2e01\u3f80\u2e01\u2e01" + + "\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u2e01\u4b02\u4b82\u4b82\u4b82" + + "\u2f02\u2f02\u4c02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02\u2f02" + + "\u2f02\u4c82\u4d02\u4d02\u3f80\u4786\u4786\u6008\u3f80\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05\u3b05" + + "\u3b05\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3f80\u3b05\u3f80\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80" + + "\u4786\u3b05\u6008\u6008\u4786\u6008\u6008\u6008\u6008\u6008\u6008" + + "\u4786\u4786\u4786\u3f80\u3f80\u3f80\u3f80\u5301\u5301\u5301\u5301" + + "\u5301\u5301\u5301\u5301\u5301\u5301\u5301\u5301\u5301\u5301\u5301" + + "\u5301\u5082\u5082\u5082\u5082\u5082\u5082\u5082\u5082\u5082\u5082" + + "\u5082\u5082\u5082\u5082\u5082\u5082\u4e81\u3001\u3082\u3001\u3082" + + "\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3001\u3082\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u6089\u6109\u6189\u6209\u6289\u6309" + + "\u6389\u6409\u6489\u6509\u6b0b\u6b0b\u6b0b\u6b0b\u6b0b\u6b0b\u539c" + + "\u4786\u539c\u4786\u539c\u4786\u6b95\u6c16\u6b95\u6c16\u6008\u6008" + + "\u4786\u4786\u4786\u3f80\u4786\u3f80\u6008\u6008\u6008\u6008\u6008" + + "\u6008\u6008\u6008\u4786\u6008\u6008\u4786\u4786\u4786\u4786\u4786" + + "\u4786\u4786\u4786\u6008\u6008\u6008\u6008\u4786\u3f80\u3f80\u5518" + + "\u5518\u5518\u5518\u5518\u5518\u5518\u5518\u6109\u6189\u6209\u6289" + + "\u6309\u6389\u6409\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786" + + "\u4786\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u2e82\u2e82\u2e82\u2e82\u2e82\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u5705\u4786\u5705\u5705\u3f80\u5705\u5705\u3f80\u5705\u5705" + + "\u5705\u5705\u5705\u5705\u5705\u5705\u5705\u5705\u5705\u5705\u5705" + + "\u5705\u5705\u5705\u3f80\u3f80\u3f80\u3f80\u3f80\u6008\u6008\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3b05\u3f80\u3b05\u3b05\u3f80" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u4786\u3b05\u6008\u4786" + + "\u4786\u4786\u4786\u4786\u3f80\u4786\u4786\u6008\u3f80\u6008\u6008" + + "\u4786\u3f80\u3f80\u0298\u0298\u0318\u039a\u0318\u0298\u0298\u0455" + + "\u04d6\u0298\u0519\u0598\u0614\u0598\u0698\u5705\u5705\u5705\u5698" + + "\u5698\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u6008\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u2d8b" + + "\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b\u2d8b" + + "\u738b\u5989\u5a09\u5a89\u5b09\u5b89\u5c09\u5c89\u5d09\u5d89\u5e09" + + "\u0318\u5e98\u5e98\u5818\u5885\u5885\u5885\u5885\u5818\u5885\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u5790\u5407\u4786\u5407\u5407" + + "\u5407\u4786\u4786\u4786\u4786\u4786\u4786\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u5818\u3f80\u3f80\u3f80\u5818\u5818\u5818\u5818\u5818\u5818" + + "\u5818\u5818\u5818\u5818\u5818\u5818\u5818\u5818\u3f80\u5f90\u5904" + + "\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u3f80" + + "\u3f80\u5885\u5885\u5885\u5885\u5885\u3f80\u5885\u5885\u5885\u5885" + + "\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u6109" + + "\u6189\u6209\u6289\u6309\u6389\u6409\u6489\u6509\u688b\u6c8b\u6d0b" + + "\u6d8b\u6e0b\u6e8b\u6f0b\u6f8b\u700b\u690b\u708b\u3f80\u3f80\u3f80" + + "\u0709\u0789\u0809\u0889\u0909\u0989\u0a09\u0a89\u0b09\u0b89\u5885" + + "\u5885\u5885\u5f1c\u5f1c\u5885\u4786\u5885\u5885\u5885\u5885\u5885" + + "\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u3f80" + + "\u3f80\u5f90\u5f90\u5f90\u5f90\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u5f90\u5f90\u5f90\u5f90\u5f90\u5f90\u4786\u4786\u4786\u4786\u4786" + + "\u5904\u5904\u4786\u4786\u289c\u4786\u4786\u4786\u4786\u5885\u5885" + + "\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\u5885\uc51a" + + "\u289c\u3f80\u3f80\u4786\u5885\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u04d6\u0298\u0455" + + "\u04d6\u0298\u1a97\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3f80\u3f80\u3f80\u3f80\u6008\u6008\u3f80\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3f80\u3f80\u3f80\u3f80\u4786\u4786\u6008\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u6b95\u6c16" + + "\u3f80\u3f80\u3f80\u020c\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u1a97\u4684\u4684\u4684\u3b05\u3b05\u3b05\u4684\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3f80\u3f80\u4786\u3b05\u6008\u6008\u6008\u6008" + + "\u6008\u3f80\u6a06\u6008\u6008\u3f80\u6008\u6008\u4786\u4786\u3f80" + + "\u3f80\u3f80\u3f80\u4786\u4786\u3f80\u3f80\u4786\u4786\u4786\u3f80" + + "\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u4786" + + "\u4786\u1a1b\u1a1b\u4684\u4684\u3b05\u4786\u4786\u4786\u4786\u3f80" + + "\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3f80\u3f80\u5518\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05\u4786\u4786" + + "\u5518\u5518\u6089\u6109\u6189\u6209\u6289\u6309\u6389\u6409\u6489" + + "\u6509\u5518\u5518\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05\u4786\u4786" + + "\u3f80\u3f80\u6089\u6109\u6189\u6209\u6289\u6309\u6389\u6409\u6489" + + "\u6509\u3f80\u3f80\u3b05\u3b05\u3f80\u3f80\u3b05\u3b05\u039a\u039a" + + "\u658b\u660b\u668b\u670b\u678b\u680b\u539c\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u4786\u4786\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3b05\u4786\u3b05\u3b05\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u3f80\u3f80\u3f80\u3f80\u039a" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u4684\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u5518\u4786\u4786\u3b05" + + "\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80\u3f80\u6089\u6109\u6189\u6209" + + "\u6289\u6309\u6389\u6409\u6489\u6509\u5518\u5518\u5518\u5518\u5518" + + "\u5518\u688b\u690b\u698b\u289c\u289c\u289c\u289c\u289c\u289c\u039a" + + "\u289c\u3f80\u3f80\u3f80\u3f80\u3f80\u4786\u6008\u6008\u6008\u6008" + + "\u3f80\u4786\u4786\u4786\u3f80\u4786\u4786\u4786\u4786\u3f80\u3f80" + + "\u3b05\u3b05\u3b05\u3b05\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80" + + "\u3f80\u4786\u3b05\u6008\u6a06\u6008\u4786\u4786\u4786\u3f80\u3f80" + + "\u6008\u6008\u6008\u3f80\u6008\u6008\u6008\u4786\u3f80\u3f80\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80\u3f80\u4786\u3f80" + + "\u3f80\u3f80\u3f80\u6008\u6008\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u5518\u5518\u5518\u710a\u718a" + + "\u3b05\u4786\u3b05\u3b05\u4786\u4786\u4786\u4786\u4786\u4786\u3f80" + + "\u4786\u4786\u3b05\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80" + + "\u4684\u3f80\u4786\u4786\u4786\u4786\u4786\u4786\u3f80\u3f80\u3b05" + + "\u539c\u539c\u539c\u5518\u5518\u5518\u5518\u5518\u5518\u5518\u5518" + + "\u6ab8\u5518\u5518\u5518\u4786\u6008\u4786\u3f80\u3f80\u3f80\u4786" + + "\u4786\u6008\u4786\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u6008\u6008\u4786\u4786\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u4e81\u4e81\u289c\u4e81\u2902\u3b05\u3b05\u3b05" + + "\u3b05\u2902\u289c\u289c\u3f80\u2902\u4e81\u4e81\u4e81\u4e81\u4e81" + + "\u4e81\u4e81\u4e81\u4e81\u4e81\u4e81\u4e81\u4e81\u4e81\u4e81\u4e81" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3b05" + + "\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u720a" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05\u4786\u4786\u4786\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3b05\u3b05" + + "\u4786\u4786\u4786\u5518\u5518\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3b05\u3b05\u4786\u4786\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3b05\u3f80\u4786" + + "\u4786\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3b05\u3b05\u3b05\u3b05\u7290\u7290\u6008\u4786\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u6008\u6008\u6008\u6008\u4786\u4786" + + "\u7808\u7808\u7808\u3f80\u3f80\u3f80\u3f80\u4786\u4786\u4786\u4786" + + "\u5518\u5518\u5518\u4684\u5518\u5518\u5518\u039a\u3b05\u4786\u3f80" + + "\u3f80\ua90b\ua98b\uaa0b\uaa8b\uab0b\u738b\u740b\u748b\u750b\u758b" + + "\u760b\u768b\u770b\u778b\uab8b\u730b\u738b\u740b\u748b\u750b\u758b" + + "\u760b\u768b\u770b\u778b\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u0298" + + "\u0298\u0298\u0298\u0298\u0298\u5614\u0298\u0298\u0298\u0298\u4786" + + "\u4786\u4786\u020c\u3f80\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05\u3b05" + + "\u3b05\u3b05\u4786\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u4e81\u4e81" + + "\u4e81\u2902\u289c\u4e81\u289c\u289c\u289c\u4e81\u4e81\u4e81\u4e81" + + "\u4e81\u289c\u289c\u0c99\u289c\u0c99\u289c\u289c\u289c\u289c\u289c" + + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" + + "\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99" + + "\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59" + + "\u0c99\u0c99\u0455\u04d6\u0c99\u0c99\u0c99\u0455\u04d6\u0455\u04d6" + + "\u0455\u04d6\u0455\u04d6\u0455\u04d6\u0455\u04d6\u0455\u04d6\u0c99" + + "\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99" + + "\u0c59\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99" + + "\u0c99\u0c99\u0c99\u0c59\u0c99\u0c59\u0c99\u0c59\u0c59\u0c59\u0c59" + + "\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59" + + "\u0c59\u0c59\u0c59\u0c99\u0c59\u0c99\u0c59\u0c59\u0c59\u0c99\u0c99" + + "\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c99\u0c99" + + "\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c59\u0c99\u0c99\u0c59" + + "\u0c59\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59" + + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c59\u0c99" + + "\u0c59\u0c99\u0c99\u0c59\u0c99\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99" + + "\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c59" + + "\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99" + + "\u0c99\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c99" + + "\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c99\u0c99\u0c99" + + "\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99" + + "\u0c99\u0c99\u289c\u289c\u289c\u289c\u289c\u0c99\u0c99\u289c\u289c" + + "\u289c\u289c\u4e81\u289c\u8c81\u289c\u4e81\u289c\u8d01\u8d81\u4e81" + + "\u4e81\u2a9c\u2902\u4684\u4684\u2902\u2902\u2902\u2902\u2902\u2902" + + "\u2902\u2902\u2902\u2902\u3f80\u3f80\u3f80\u3f80\u7902\u7902\u7902" + + "\u7902\u7902\u7902\u7902\u7902\u7981\u7981\u7981\u7981\u7981\u7981" + + "\u7981\u7981\u7902\u7902\u7902\u7902\u7902\u7902\u3f80\u3f80\u7981" + + "\u7981\u7981\u7981\u7981\u7981\u3f80\u3f80\u2e82\u7902\u4a82\u7902" + + "\u4a82\u7902\u4a82\u7902\u3f80\u7981\u3f80\u7981\u3f80\u7981\u3f80" + + "\u7981\u7a02\u7a02\u7a82\u7a82\u7a82\u7a82\u7b02\u7b02\u7b82\u7b82" + + "\u7c02\u7c02\u7c82\u7c82\u3f80\u3f80\u7d02\u7d02\u7d02\u7d02\u7d02" + + "\u7d02\u7d02\u7d02\u7d83\u7d83\u7d83\u7d83\u7d83\u7d83\u7d83\u7d83" + + "\u7902\u7902\u2e82\u7e02\u2e82\u3f80\u2e82\u4a82\u7981\u7981\u7e81" + + "\u7e81\u7f03\u1a1b\u7f82\u1a1b\u7902\u7902\u4a82\u4a82\u3f80\u3f80" + + "\u2e82\u4a82\u7981\u7981\u8081\u8081\u3f80\u1a1b\u1a1b\u1a1b\u7902" + + "\u7902\u4a82\u4a82\u2e82\u5102\u2e82\u4a82\u7981\u7981\u8101\u8101" + + "\u5281\u1a1b\u1a1b\u1a1b\u020c\u020c\u020c\u020c\u020c\u020c\u020c" + + "\u82ac\u020c\u020c\u020c\u830c\u5f90\u5f90\u7290\u8390\u5614\u8434" + + "\u5614\u5614\u5614\u5614\u0298\u0298\u849d\u851e\u6b95\u849d\u849d" + + "\u851e\u6b95\u849d\u0598\u0298\u0598\u3f80\u0298\u0598\u0298\u0298" + + "\u5614\u6b95\u6c16\u6b95\u6c16\u6b95\u6c16\u0318\u0318\u0318\u0318" + + "\u0318\u0298\u0298\u0298\u0298\u29dd\u2d5e\u0298\u0298\u0298\u0298" + + "\u1a97\u890b\u2902\u3f80\u3f80\u898b\u8a0b\u8a8b\u8b0b\u8b8b\u8c0b" + + "\u0519\u0519\u0c99\u0455\u04d6\u2902\u890b\u2c8b\u2b0b\u2b8b\u898b" + + "\u8a0b\u8a8b\u8b0b\u8b8b\u8c0b\u0519\u0519\u0c99\u0455\u04d6\u3f80" + + "\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a\u039a" + + "\u039a\u039a\u039a\u039a\u039a\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u4786\u4786\u4786" + + "\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u4786\u5407" + + "\u5407\u5407\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99" + + "\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59\u0c59" + + "\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59" + + "\u0c59\u0c59\u0c59\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59" + + "\u0c59\u0c99\u0c99\u0c59\u0c59\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59" + + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59" + + "\u0c59\u0c99\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c99\u0c99\u0c99" + + "\u0c99\u0c59\u0c59\u0c59\u0c59\u0c99\u0c59\u0519\u0519\u0c99\u0c59" + + "\u0c59\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c99\u0c59\u0c99" + + "\u0c59\u0c99\u0c99\u0c99\u0c99\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59" + + "\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c59\u0c99\u0c59\u0c59\u0c99" + + "\u0c99\u0455\u04d6\u0455\u04d6\u0c59\u0c99\u0c99\u0c99\u0c99\u4e81" + + "\u2902\u2902\u2902\u2902\u289c\u0c99\u3f80\u3f80\u3f80\u3f80\u8e0a" + + "\u8e8a\u8f0a\u8f8a\u900a\u908a\u910a\u918a\u920a\u928a\u930a\u938a" + + "\u940a\u948a\u950a\u958a\u960a\u968a\u970a\u978a\u980a\u988a\u990a" + + "\u998a\u9a0a\u9a8a\u9b0a\u9b8a\u9c0a\u9c8a\u9d0a\u9d8a\u9e0a\u9e8a" + + "\u9f0a\u9f8a\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u0c99\u289c\u289c\u0c99\u289c\u289c\u0c99\u289c" + + "\u289c\u289c\u289c\u289c\u289c\u289c\u0c99\u289c\u289c\u289c\u289c" + + "\u289c\u289c\u289c\u289c\u0c59\u0c59\u0c59\u0c59\u289c\u289c\u289c" + + "\u289c\u289c\u289c\u289c\u0455\u04d6\u289c\u289c\u289c\u289c\u289c" + + "\u289c\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c" + + "\u539c\u539c\u539c\u539c\u539c\u539c\u289c\u289c\u3f80\u539c\ubc8b" + + "\ubd0b\ubd8b\ube0b\ube8b\ubf0b\ubf8b\uc00b\uc08b\uc10b\uc18b\uc20b" + + "\uc28b\uc30b\uc38b\u768b\u770b\u778b\uab8b\u289c\u3f80\u3f80\u3f80" + + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u289c" + + "\u289c\u289c\u289c\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\ua18b\ua20b\ua28b\ua30b" + + "\ua38b\ua40b\ua48b\ua50b\u2c8b\u2b0b\u2b8b\u898b\u8a0b\u8a8b\u8b0b" + + "\u8b8b\u8c0b\ua00b\ua08b\ua10b\ua18b\ua20b\ua28b\ua30b\ua38b\ua40b" + + "\ua48b\ua50b\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c" + + "\u539c\u539c\u539c\u289c\u289c\u289c\u289c\u539c\u539c\u539c\u539c" + + "\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c\u539c" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80" + + "\u3f80\u658b\u660b\u668b\u670b\ub28b\ub30b\ub38b\ub40b\ub48b\u688b" + + "\u539c\u539c\u539c\u539c\u539c\u539c\ua59c\ua59c\ua59c\ua59c\ua59c" + + "\ua59c\ua59c\ua59c\ua59c\ua59c\ua59c\ua59c\ua59c\ua59c\ua59c\ua59c" + + "\ua61c\ua61c\ua61c\ua61c\ua61c\ua61c\ua61c\ua61c\ua61c\ua61c\ua61c" + + "\ua61c\ua61c\ua61c\ua61c\ua61c\u890b\ua68b\ua70b\ua78b\ua80b\ua88b" + + "\u5614\u4684\u4684\u4684\u4684\u4684\u289c\u289c\ub10a\ub18a\ub20a" + + "\u4684\u3b05\u0298\u289c\u289c\u289c\u3f80\u3f80\u3f80\u289c\u3f80" + + "\u289c\u289c\u289c\u289c\u289c\u289c\u289c\u3f80\u0c99\u0c99\u0c59" + + "\u0c59\u0c59\u0c59\u0455\u04d6\u0455\u04d6\u0455\u04d6\u3f80\u3f80" + + "\u3f80\u3f80\u020c\u0298\u0298\u0298\u289c\u4684\u3b05\uac0a\u0455" + + "\u04d6\u0455\u04d6\u0455\u04d6\u0455\u04d6\u289c\u289c\u0455\u04d6" + + "\u0455\u04d6\u0455\u04d6\u0455\u04d6\u5614\u6b95\u6c16\u6c16\u289c" + + "\ub50b\ub58b\ub60b\ub68b\ub70b\ub78b\ub80b\ub88b\ub90b\ub98b\uba0b" + + "\uba8b\ubb0b\ubb8b\ubc0b\uc413\uc413\uc413\uc413\uc413\uc413\uc413" + + "\uc413\uc413\uc413\uc413\uc413\uc413\uc413\uc413\uc413\uc492\uc492" + + "\uc492\uc492\uc492\uc492\uc492\uc492\uc492\uc492\uc492\uc492\uc492" + + "\uc492\uc492\uc492\u2e82\u2e82\u2e82\u4a82\u4a82\u2e82\u2e82\u3f80" + + "\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u3f80\u5705\u5705\u5705" + + "\u5705\u5705\u5705\u5705\u5705\u5705\u0519\u5705\u5705\u5705\u5705" + + "\u5705\u5705\u5705\u3f80\u5705\u5705\u5705\u5705\u5705\u3f80\u5705" + + "\u3f80\u0298\u5614\u5614\u1a97\u1a97\u6b95\u6c16\u6b95\u6c16\u6b95" + + "\u6c16\u6b95\u6c16\u6b95\u6c16\u6b95\u6c16\u0298\u0298\u6b95\u6c16" + + "\u0298\u0298\u0298\u0298\u1a97\u1a97\u1a97\u0298\u0298\u0519\u0614" + + "\u0c99\u0c99\u0c99\u3f80\u0298\u039a\u0318\u0298\u3f80\u3f80\u3f80" + + "\u3f80\u2282\u2302\u2382\u2402\u2482\u2502\u2582\u2602\u2682\u2702" + + "\u2782\u0455\u0c99\u04d6\u0c99\u0455\u039a\u039a\u0c99\u1a1b\u289c" + + "\u039a\u039a\u3f80\u289c\u0c99\u0c99\u0c99\u0c99\u289c\u289c\u3f80", + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\u0080\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\u0080\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\u0080\005\005\u0080\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\u0080\u0080\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u1981\u1981\u1981\u1981\u1981" + + "\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981" + + "\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981" + + "\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981\u1981" + + "\u1981\u1981\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02" + + "\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02\u1a02" + + "\u1a02\u1a02\u1a02\u1a02\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\u0080\u0080\u0080\u0080\u0080\u0118\u0198\u021c\u0080" + + "\u0080\u0080\u0080\u028b\u030b\u038b\u040b\u048b\u050b\u058b\u060b" + + "\u068b\u070b\u078b\u080b\u088b\u090b\u098b\u0a0b\u0a8b\u0b0b\u0b8b" + + "\u0c0b\u0c8b\u0d0b\u0d8b\u0e0b\u0e8b\u0f0b\u0f8b\u100b\u108b\u110b" + + "\u118b\u120b\u128b\u130b\u138b\u140b\u148b\u150b\u158b\u160b\u168b" + + "\u170b\u178b\u180b\u188b\u0080\u0080\u0080\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u2008\u2008\u2086\u2086\u2086\u021c\u021c\u021c\u2008\u2008\u2008" + + "\u2008\u2008\u2008\u2110\u2110\u2110\u2110\u2110\u2110\u2110\u2110" + + "\u2086\u2086\u2086\u2086\u2086\u021c\u021c\u2086\u2086\u2086\u2086" + + "\u2086\u2086\u2086\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u2086\u2086\u2086\u2086\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u0080" + + "\u0080\u0080\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c\u021c" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\005\005\005\005\005\005\005\005\005\005" + + "\u190a\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\u0080\u028b\u048b" + + "\u070b\u090b\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\u0080\u0118\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\u0080\u0080" + + "\u1a89\u1b09\u1b89\u1c09\u1c89\u1d09\u1d89\u1e09\u1e89\u1f09\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u1f85" + + "\u1f85\u1f85\u1f85\u1f85\u1f85\u0080\u0080\u1f85\u0080\u1f85\u1f85" + + "\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85" + + "\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85" + + "\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85" + + "\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u1f85\u0080\u1f85" + + "\u1f85\u0080\u0080\u0080\u1f85\u0080\u0080\u1f85\u219c\u219c\u219c" + + "\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c" + + "\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c" + + "\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c" + + "\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c" + + "\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c\u219c" + + "\u219c\u219c\u219c\u219c\u219c\u219c\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u2201\u2319\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2319\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2319\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u0080\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u0080\u0080\u0080\u0080\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u0080\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u0080\u2201\u0080\u0080\u0080\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u0080\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2201\u0080\u2201\u2201\u0080\u0080\u2201\u0080\u0080\u2201" + + "\u2201\u0080\u0080\u2201\u2201\u2201\u2201\u0080\u2201\u2201\u2201" + + "\u2201\u2201\u2201\u2201\u2201\u2282\u2282\u2282\u2282\u0080\u2282" + + "\u0080\u2282\u2282\u2282\u2282\u2201\u2201\u0080\u2201\u2201\u2201" + + "\u2201\u0080\u0080\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u2201" + + "\u0080\u2201\u2201\u2201\u2201\u2201\u2201\u2201\u0080\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282\u2282" + + "\u2282\u2282\u2201\u2201\u0080\u2201\u2201\u2201\u2201\u0080\u2282" + + "\u2282\u2282\u2319\u2282\u2282\u2282\u2282\u2282\u2282\u0080\u0080" + + "\u0080\u0080\u2389\u2409\u2489\u2509\u2589\u2609\u2689\u2709\u2789" + + "\u2809\u2389\u2409\u2489\u2509\u2589\u2609\u2689\u2709\u2789\u2809" + + "\u2389\u2409\u2489\u2509\u2589\u2609\u2689\u2709\u2789\u2809\u2389" + + "\u2409\u2489\u2509\u2589\u2609\u2689\u2709\u2789\u2809\u2389\u2409" + + "\u2489\u2509\u2589\u2609\u2689\u2709\u2789\u2809", + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\005\005\005\005" + + "\005\005\005\005\005\005\005\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080\u0080" + + "\u0080\u0080\u0080", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "", + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106\u0106" + + "\u0106\u0106\u0106\u0106\u0106\u0106\u0106\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\u0090\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\000\000\000\000\000\000\000\000\000\000" + + "\000\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090" + + "\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090\u0090", + + "", + + ""}; + + /** + * This is the attribute table for computing the numeric value of a + * character. The value is -1 if Unicode does not define a value, -2 + * if the value is not a positive integer, otherwise it is the value. + * Note that this is a signed value, but stored as an unsigned char + * since this is a String literal. + */ + String[] NUM_VALUE = new String[]{ + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff" + + "\uffff\uffff\uffff\000\001\002\003\004\005\006\007" + + "\010\011\uffff\uffff\012\013\014\015\016\017\020" + + "\021\022\023\024\025\026\027\030\031\032\033" + + "\034\035\036\037 !\"#\uffff\uffff\012" + + "\013\014\015\016\017\020\021\022\023\024\025" + + "\026\027\030\031\032\033\034\035\036\037 " + + "!\"#\uffff\uffff\uffff\uffff\uffff\uffff\002\003" + + "\uffff\001\uffff\ufffe\uffff\uffff\uffff\uffff\uffff\uffff\uffff" + + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff" + + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff" + + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff" + + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff" + + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff" + + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff" + + "\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff\uffff" + + "\uffff\uffff\uffff\000\001\002\003\004\005\006\007" + + "\010\011\uffff\uffff\uffff\uffff\000\001\002\003\004" + + "\005\006\007\010\011\001\002\003\004\uffff\020" + + "\012d\u03e8\uffff\uffff\ufffe\uffff\uffff\024\036(" + + "2UPPER to determine their titlecase). The listing + * is a sorted sequence of character pairs; converting the first character + * of the pair to titlecase produces the second character. + */ + String TITLE + = "\u01c4\u01c5\u01c5\u01c5\u01c6\u01c5\u01c7\u01c8\u01c8\u01c8\u01c9" + + "\u01c8\u01ca\u01cb\u01cb\u01cb\u01cc\u01cb\u01f1\u01f2\u01f2\u01f2" + + "\u01f3\u01f2"; + + /** + * This is a listing of characters with multi-character uppercase sequences. + * A character appears in this list exactly when it has a non-zero entry + * in the low-order 2-bit field of DIRECTION. The listing is a sorted + * sequence of pairs (hence a binary search on the even elements is an + * efficient way to lookup a character). The first element of a pair is the + * character with the expansion, and the second is the index into + * UPPER_EXPAND where the expansion begins. Use the 2-bit field of + * DIRECTION to determine where the expansion ends. + */ + String UPPER_SPECIAL + = "\u00df\000\u0149\002\u01f0\004\u0390\006\u03b0\011" + + "\u0587\014\u1e96\016\u1e97\020\u1e98\022\u1e99\024" + + "\u1e9a\026\u1f50\030\u1f52\032\u1f54\035\u1f56 " + + "\u1f80#\u1f81%\u1f82'\u1f83)\u1f84+" + + "\u1f85-\u1f86/\u1f871\u1f883\u1f895" + + "\u1f8a7\u1f8b9\u1f8c;\u1f8d=\u1f8e?" + + "\u1f8fA\u1f90C\u1f91E\u1f92G\u1f93I" + + "\u1f94K\u1f95M\u1f96O\u1f97Q\u1f98S" + + "\u1f99U\u1f9aW\u1f9bY\u1f9c[\u1f9d]" + + "\u1f9e_\u1f9fa\u1fa0c\u1fa1e\u1fa2g" + + "\u1fa3i\u1fa4k\u1fa5m\u1fa6o\u1fa7q" + + "\u1fa8s\u1fa9u\u1faaw\u1faby\u1fac{" + + "\u1fad}\u1fae\u007f\u1faf\u0081\u1fb2\u0083\u1fb3\u0085" + + "\u1fb4\u0087\u1fb6\u0089\u1fb7\u008b\u1fbc\u008e\u1fc2\u0090" + + "\u1fc3\u0092\u1fc4\u0094\u1fc6\u0096\u1fc7\u0098\u1fcc\u009b" + + "\u1fd2\u009d\u1fd3\u00a0\u1fd6\u00a3\u1fd7\u00a5\u1fe2\u00a8" + + "\u1fe3\u00ab\u1fe4\u00ae\u1fe6\u00b0\u1fe7\u00b2\u1ff2\u00b5" + + "\u1ff3\u00b7\u1ff4\u00b9\u1ff6\u00bb\u1ff7\u00bd\u1ffc\u00c0" + + "\ufb00\u00c2\ufb01\u00c4\ufb02\u00c6\ufb03\u00c8\ufb04\u00cb" + + "\ufb05\u00ce\ufb06\u00d0\ufb13\u00d2\ufb14\u00d4\ufb15\u00d6" + + "\ufb16\u00d8\ufb17\u00da"; + + /** + * This is the listing of special case multi-character uppercase sequences. + * Characters listed in UPPER_SPECIAL index into this table to find their + * uppercase expansion. Remember that you must also perform special-casing + * on two single-character sequences in the Turkish locale, which are not + * covered here in CharData. + */ + String UPPER_EXPAND + = "SS\u02bcNJ\u030c\u0399\u0308\u0301\u03a5\u0308" + + "\u0301\u0535\u0552H\u0331T\u0308W\u030aY\u030a" + + "A\u02be\u03a5\u0313\u03a5\u0313\u0300\u03a5\u0313\u0301\u03a5" + + "\u0313\u0342\u1f08\u0399\u1f09\u0399\u1f0a\u0399\u1f0b\u0399\u1f0c" + + "\u0399\u1f0d\u0399\u1f0e\u0399\u1f0f\u0399\u1f08\u0399\u1f09\u0399" + + "\u1f0a\u0399\u1f0b\u0399\u1f0c\u0399\u1f0d\u0399\u1f0e\u0399\u1f0f" + + "\u0399\u1f28\u0399\u1f29\u0399\u1f2a\u0399\u1f2b\u0399\u1f2c\u0399" + + "\u1f2d\u0399\u1f2e\u0399\u1f2f\u0399\u1f28\u0399\u1f29\u0399\u1f2a" + + "\u0399\u1f2b\u0399\u1f2c\u0399\u1f2d\u0399\u1f2e\u0399\u1f2f\u0399" + + "\u1f68\u0399\u1f69\u0399\u1f6a\u0399\u1f6b\u0399\u1f6c\u0399\u1f6d" + + "\u0399\u1f6e\u0399\u1f6f\u0399\u1f68\u0399\u1f69\u0399\u1f6a\u0399" + + "\u1f6b\u0399\u1f6c\u0399\u1f6d\u0399\u1f6e\u0399\u1f6f\u0399\u1fba" + + "\u0399\u0391\u0399\u0386\u0399\u0391\u0342\u0391\u0342\u0399\u0391" + + "\u0399\u1fca\u0399\u0397\u0399\u0389\u0399\u0397\u0342\u0397\u0342" + + "\u0399\u0397\u0399\u0399\u0308\u0300\u0399\u0308\u0301\u0399\u0342" + + "\u0399\u0308\u0342\u03a5\u0308\u0300\u03a5\u0308\u0301\u03a1\u0313" + + "\u03a5\u0342\u03a5\u0308\u0342\u1ffa\u0399\u03a9\u0399\u038f\u0399" + + "\u03a9\u0342\u03a9\u0342\u0399\u03a9\u0399FFFI" + + "FLFFIFFLSTS" + + "T\u0544\u0546\u0544\u0535\u0544\u053b\u054e\u0546\u0544\u053d"; +} diff --git a/libjava/classpath/gnu/java/lang/ClassHelper.java b/libjava/classpath/gnu/java/lang/ClassHelper.java new file mode 100644 index 000000000..e190889de --- /dev/null +++ b/libjava/classpath/gnu/java/lang/ClassHelper.java @@ -0,0 +1,205 @@ +/* ClassHelper.java -- Utility methods to augment java.lang.Class + Copyright (C) 1998, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.lang; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Map; +import java.util.Set; + +/** + * ClassHelper has various methods that ought to have been in Class. + * + * @author John Keiser + * @author Eric Blake (ebb9@email.byu.edu) + */ +public class ClassHelper +{ + /** + * Strip the package part from the class name. + * + * @param clazz the class to get the truncated name from + * @return the truncated class name + */ + public static String getTruncatedClassName(Class clazz) + { + return getTruncatedName(clazz.getName()); + } + + /** + * Strip the package part from the class name, or the class part from + * the method or field name. + * + * @param name the name to truncate + * @return the truncated name + */ + public static String getTruncatedName(String name) + { + int lastInd = name.lastIndexOf('.'); + if (lastInd == -1) + return name; + return name.substring(lastInd + 1); + } + + /** + * Return the name of the class as written by the user. + * This is used by the various reflection toString methods. + * It differs from {@link Class#getName()} in that it prints + * arrays with trailing "[]"s. Note that it does not treat + * member classes specially, so a dollar sign may still appear + * in the result. This is intentional. + * @param klass the class + * @return a pretty form of the class' name + */ + public static String getUserName(Class klass) + { + int arrayCount = 0; + while (klass.isArray()) + { + ++arrayCount; + klass = klass.getComponentType(); + } + String name = klass.getName(); + if (arrayCount == 0) + return name; + CPStringBuilder b = new CPStringBuilder(name.length() + 2 * arrayCount); + b.append(name); + for (int i = 0; i < arrayCount; ++i) + b.append("[]"); + return b.toString(); + } + + /** Cache of methods found in getAllMethods(). */ + private static Map allMethods = new HashMap(); + + /** + * Get all the methods, public, private and otherwise, from the class, + * getting them from the most recent class to find them. This may not + * be quite the correct approach, as this includes methods that are not + * inherited or accessible from clazz, so beware. + * + * @param clazz the class to start at + * @return all methods declared or inherited in clazz + */ + public static Method[] getAllMethods(Class clazz) + { + Method[] retval = (Method[]) allMethods.get(clazz); + if (retval == null) + { + Set methods = new HashSet(); + Class c = clazz; + while (c != null) + { + Method[] currentMethods = c.getDeclaredMethods(); + loop: + for (int i = 0; i < currentMethods.length; i++) + { + Method current = currentMethods[i]; + int size = methods.size(); + Iterator iter = methods.iterator(); + while (--size >= 0) + { + Method override = (Method) iter.next(); + if (current.getName().equals(override.getName()) + && Arrays.equals(current.getParameterTypes(), + override.getParameterTypes()) + && current.getReturnType() == override.getReturnType()) + continue loop; + } + methods.add(current); + } + c = c.getSuperclass(); + } + retval = new Method[methods.size()]; + methods.toArray(retval); + allMethods.put(clazz, retval); + } + return retval; + } + + /** Cache of fields found in getAllFields(). */ + private static Map allFields = new HashMap(); + + /** + * Get all the fields, public, private and otherwise, from the class, + * getting them from the most recent class to find them. This may not + * be quite the correct approach, as this includes fields that are not + * inherited or accessible from clazz, so beware. + * + * @param clazz the class to start at + * @return all fields declared or inherited in clazz + */ + public static Field[] getAllFields(Class clazz) + { + Field[] retval = (Field[]) allFields.get(clazz); + if (retval == null) + { + Set fields = new HashSet(); + Class c = clazz; + while (c != null) + { + Field[] currentFields = c.getDeclaredFields(); + loop: + for (int i = 0; i < currentFields.length; i++) + { + Field current = currentFields[i]; + int size = fields.size(); + Iterator iter = fields.iterator(); + while (--size >= 0) + { + Field override = (Field) iter.next(); + if (current.getName().equals(override.getName()) + && current.getType() == override.getType()) + continue loop; + } + fields.add(current); + } + c = c.getSuperclass(); + } + retval = new Field[fields.size()]; + fields.toArray(retval); + allFields.put(clazz, retval); + } + return retval; + } +} diff --git a/libjava/classpath/gnu/java/lang/InstrumentationImpl.java b/libjava/classpath/gnu/java/lang/InstrumentationImpl.java new file mode 100644 index 000000000..a601baf55 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/InstrumentationImpl.java @@ -0,0 +1,241 @@ +/* InstrumentationImpl.java -- GNU implementation of + java.lang.instrument.Instrumentation + Copyright (C) 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.lang; + +import java.lang.instrument.Instrumentation; +import java.lang.instrument.ClassFileTransformer; +import java.lang.instrument.ClassDefinition; +import java.lang.instrument.UnmodifiableClassException; +import java.lang.instrument.IllegalClassFormatException; + +import java.security.ProtectionDomain; + +import java.util.ArrayList; +import java.util.Iterator; + +/** + * An Instrumentation object has transformers that will + * be called each time a class is defined or redefined. + * The object is given to a premain function + * that is called before the main function. + * + * @author Nicolas Geoffray (nicolas.geoffray@menlina.com) + * @since 1.5 + */ +public final class InstrumentationImpl implements Instrumentation +{ + + /* List of transformers */ + private ArrayList transformers = + new ArrayList(); + + + InstrumentationImpl() + { + } + + /** + * Adds a ClassFileTransformer object + * to the instrumentation. Each time a class is defined + * or redefined, the transform method of the + * transformer object is called. + * + * @param transformer the transformer to add + * @throws NullPointerException if transformer is null + */ + public void addTransformer(ClassFileTransformer transformer) + { + if (transformer == null) + throw new NullPointerException(); + synchronized(transformers) + { + transformers.add(transformer); + } + } + + /** + * Removes the given transformer from the set of transformers + * this Instrumentation object has. + * + * @param transformer the transformer to remove + * @return true if the transformer was found and removed, false if + * the transformer was not found + * @throws NullPointerException if transformer is null + */ + public boolean removeTransformer(ClassFileTransformer transformer) + { + if (transformer == null) + throw new NullPointerException(); + + boolean result; + synchronized (transformers) + { + result = transformers.remove(transformer); + } + return result; + } + + /** + * Returns if the current JVM supports class redefinition + * + * @return true if the current JVM supports class redefinition + */ + public boolean isRedefineClassesSupported() + { + return VMInstrumentationImpl.isRedefineClassesSupported(); + } + + /** + * Redefine classes present in the definitions array, with + * the corresponding class files. + * + * @param definitions an array of classes to redefine + * + * @throws ClassNotFoundException if a class cannot be found + * @throws UnmodifiableClassException if a class cannot be modified + * @throws UnsupportedOperationException if the JVM does not support + * redefinition or the redefinition made unsupported changes + * @throws ClassFormatError if a class file is not valid + * @throws NoClassDefFoundError if a class name is not equal to the name + * in the class file specified + * @throws UnsupportedClassVersionError if the class file version numbers + * are unsupported + * @throws ClassCircularityError if circularity occured with the new + * classes + * @throws LinkageError if a linkage error occurs + * @throws NullPointerException if the definitions array is null, or any + * of its element + * + * @see isRedefineClassesSupported() + * @see addTransformer(java.lang.instrument.ClassFileTransformer) + * @see ClassFileTransformer + */ + public void redefineClasses(ClassDefinition[] definitions) + throws ClassNotFoundException, + UnmodifiableClassException + { + if (!isRedefineClassesSupported()) + throw new UnsupportedOperationException(); + + VMInstrumentationImpl.redefineClasses(this, definitions); + } + + + /** + * Get all the classes loaded by the JVM. + * + * @return an array containing all the classes loaded by the JVM. The array + * is empty if no class is loaded. + */ + public Class[] getAllLoadedClasses() + { + return VMInstrumentationImpl.getAllLoadedClasses(); + } + + /** + * Get all the classes loaded by a given class loader + * + * @param loader the loader + * + * @return an array containing all the classes loaded by the given loader. + * The array is empty if no class was loaded by the loader. + */ + public Class[] getInitiatedClasses(ClassLoader loader) + { + return VMInstrumentationImpl.getInitiatedClasses(loader); + } + + /** + * Get the size of an object. + * + * @param objectToSize the object + * @return the size of the object + * @throws NullPointerException if objectToSize is null. + */ + public long getObjectSize(Object objectToSize) + { + // We alleviate the VM work + if (objectToSize == null) + throw new NullPointerException(); + return VMInstrumentationImpl.getObjectSize(objectToSize); + } + + /** + * Called by the VM or redefineClasses to call each transformer + * + * @param loader the loader of the class + * @param className the name of the class with packages separated with "/" + * @param classBeingRedefined the class being redefined if it's the case, + * null otherwise + * @param protectionDomain the protection domain of the class being defined + * or redefined + * @param classfileBuffer the input byte buffer in class file format + * + * @return the new class file + */ + public byte[] callTransformers(ClassLoader loader, String className, + Class classBeingRedefined, ProtectionDomain protectionDomain, + byte[] classfileBuffer) + { + byte[] newBuffer = null; + byte[] oldBuffer = classfileBuffer; + ClassFileTransformer current; + synchronized (transformers) + { + Iterator i = transformers.iterator(); + while (i.hasNext()) + { + current = i.next(); + try + { + newBuffer = current.transform(loader, className, + classBeingRedefined, protectionDomain, oldBuffer); + } + catch (IllegalClassFormatException ignored) + { + //IGNORED + } + if (newBuffer != null) + oldBuffer = newBuffer; + } + } + return oldBuffer; + } +} diff --git a/libjava/classpath/gnu/java/lang/MainThread.java b/libjava/classpath/gnu/java/lang/MainThread.java new file mode 100644 index 000000000..a72956421 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/MainThread.java @@ -0,0 +1,83 @@ +/* MainThread.java -- + Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.lang; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * MainThread is a Thread which uses the main() method of some class. + * + * @author John Keiser + * @author Tom Tromey (tromey@redhat.com) + */ +public class MainThread +{ + // Private data. + String[] args; + Method mainMethod; + + public MainThread(String classname, String[] args) + throws ClassNotFoundException, NoSuchMethodException + { + Class found = Class.forName(classname, true, + ClassLoader.getSystemClassLoader()); + Class[] argTypes = new Class[1]; + argTypes[0] = args.getClass(); + mainMethod = found.getMethod("main", argTypes); + this.args = args; + } + + public void run() + { + try + { + mainMethod.invoke(null,(Object) args); + } + catch(IllegalAccessException e) + { + // Ignore. + } + catch(InvocationTargetException e) + { + // Ignore. + } + } +} diff --git a/libjava/classpath/gnu/java/lang/management/BeanImpl.java b/libjava/classpath/gnu/java/lang/management/BeanImpl.java new file mode 100644 index 000000000..a7c2357b6 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/BeanImpl.java @@ -0,0 +1,447 @@ +/* BeanImpl.java - A common superclass for bean implementations. + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.lang.management; + +import gnu.javax.management.Translator; + +import java.lang.management.ManagementPermission; + +import java.lang.reflect.Array; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import javax.management.AttributeNotFoundException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanConstructorInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.MBeanOperationInfo; +import javax.management.MBeanParameterInfo; +import javax.management.NotCompliantMBeanException; +import javax.management.ReflectionException; +import javax.management.StandardMBean; + +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenMBeanAttributeInfo; +import javax.management.openmbean.OpenMBeanAttributeInfoSupport; +import javax.management.openmbean.OpenMBeanConstructorInfo; +import javax.management.openmbean.OpenMBeanConstructorInfoSupport; +import javax.management.openmbean.OpenMBeanInfo; +import javax.management.openmbean.OpenMBeanInfoSupport; +import javax.management.openmbean.OpenMBeanOperationInfo; +import javax.management.openmbean.OpenMBeanOperationInfoSupport; +import javax.management.openmbean.OpenMBeanParameterInfo; +import javax.management.openmbean.OpenMBeanParameterInfoSupport; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.TabularData; +import javax.management.openmbean.TabularDataSupport; +import javax.management.openmbean.TabularType; + +/** + * A common superclass for bean implementations. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class BeanImpl + extends StandardMBean +{ + + /** + * Cached open bean information. + */ + private OpenMBeanInfo openInfo; + + /** + * Constructs a new BeanImpl. + * + * @param iface the bean interface being implemented. + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + protected BeanImpl(Class iface) + throws NotCompliantMBeanException + { + super(iface); + } + + protected void cacheMBeanInfo(MBeanInfo info) + { + if (info == null) + return; + try + { + MBeanAttributeInfo[] oldA = info.getAttributes(); + OpenMBeanAttributeInfo[] attribs = + new OpenMBeanAttributeInfoSupport[oldA.length]; + for (int a = 0; a < oldA.length; ++a) + { + OpenMBeanParameterInfo param = Translator.translate(oldA[a].getType()); + if (param.getMinValue() == null) + { + Object[] lv; + if (param.getLegalValues() == null) + lv = null; + else + lv = param.getLegalValues().toArray(); + attribs[a] = new OpenMBeanAttributeInfoSupport(oldA[a].getName(), + oldA[a].getDescription(), + ((OpenType) + param.getOpenType()), + oldA[a].isReadable(), + oldA[a].isWritable(), + oldA[a].isIs(), + param.getDefaultValue(), + lv); + } + else + attribs[a] = new OpenMBeanAttributeInfoSupport(oldA[a].getName(), + oldA[a].getDescription(), + ((OpenType) + param.getOpenType()), + oldA[a].isReadable(), + oldA[a].isWritable(), + oldA[a].isIs(), + param.getDefaultValue(), + ((Comparable) + param.getMinValue()), + ((Comparable) + param.getMaxValue())); + } + MBeanConstructorInfo[] oldC = info.getConstructors(); + OpenMBeanConstructorInfo[] cons = new OpenMBeanConstructorInfoSupport[oldC.length]; + for (int a = 0; a < oldC.length; ++a) + cons[a] = + new OpenMBeanConstructorInfoSupport(oldC[a].getName(), + oldC[a].getDescription(), + translateSignature(oldC[a].getSignature())); + MBeanOperationInfo[] oldO = info.getOperations(); + OpenMBeanOperationInfo[] ops = new OpenMBeanOperationInfoSupport[oldO.length]; + for (int a = 0; a < oldO.length; ++a) + ops[a] = + new OpenMBeanOperationInfoSupport(oldO[a].getName(), + oldO[a].getDescription(), + translateSignature(oldO[a].getSignature()), + Translator.translate(oldO[a].getReturnType()).getOpenType(), + oldO[a].getImpact()); + openInfo = new OpenMBeanInfoSupport(info.getClassName(), info.getDescription(), + attribs, cons, ops, info.getNotifications()); + } + catch (OpenDataException e) + { + throw (InternalError) (new InternalError("A problem occurred creating the open type " + + "descriptors.").initCause(e)); + } + } + + protected void checkMonitorPermissions() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new ManagementPermission("monitor")); + } + + protected void checkControlPermissions() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new ManagementPermission("control")); + } + + public Object getAttribute(String attribute) + throws AttributeNotFoundException, MBeanException, + ReflectionException + { + Object value = super.getAttribute(attribute); + if (value instanceof Enum) + return ((Enum) value).name(); + Class vClass = value.getClass(); + if (vClass.isArray()) + vClass = vClass.getComponentType(); + String cName = vClass.getName(); + String[] allowedTypes = OpenType.ALLOWED_CLASSNAMES; + for (int a = 0; a < allowedTypes.length; ++a) + if (cName.equals(allowedTypes[a])) + return value; + OpenMBeanInfo info = (OpenMBeanInfo) getMBeanInfo(); + MBeanAttributeInfo[] attribs = + (MBeanAttributeInfo[]) info.getAttributes(); + OpenType type = null; + for (int a = 0; a < attribs.length; ++a) + if (attribs[a].getName().equals(attribute)) + type = ((OpenMBeanAttributeInfo) attribs[a]).getOpenType(); + if (value instanceof List) + { + try + { + Class e = + Class.forName(((ArrayType) type).getElementOpenType().getClassName()); + List l = (List) value; + Object[] array = (Object[]) Array.newInstance(e, l.size()); + return l.toArray(array); + } + catch (ClassNotFoundException e) + { + throw (InternalError) (new InternalError("The class of the list " + + "element type could not " + + "be created").initCause(e)); + } + } + if (value instanceof Map) + { + TabularType ttype = (TabularType) type; + TabularData data = new TabularDataSupport(ttype); + Iterator it = ((Map) value).entrySet().iterator(); + while (it.hasNext()) + { + Map.Entry entry = (Map.Entry) it.next(); + try + { + data.put(new CompositeDataSupport(ttype.getRowType(), + new String[] { + "key", + "value" + }, + new Object[] { + entry.getKey(), + entry.getValue() + })); + } + catch (OpenDataException e) + { + throw (InternalError) (new InternalError("A problem occurred " + + "converting the map " + + "to a composite data " + + "structure.").initCause(e)); + } + } + return data; + } + CompositeType cType = (CompositeType) type; + Set names = cType.keySet(); + Iterator it = names.iterator(); + List values = new ArrayList(names.size()); + while (it.hasNext()) + { + String field = (String) it.next(); + Method getter = null; + try + { + getter = vClass.getMethod("get" + field); + } + catch (NoSuchMethodException e) + { + /* Ignored; the type tells us it's there. */ + } + try + { + values.add(getter.invoke(value)); + } + catch (IllegalAccessException e) + { + throw new ReflectionException(e, "Failed to retrieve " + field); + } + catch (IllegalArgumentException e) + { + throw new ReflectionException(e, "Failed to retrieve " + field); + } + catch (InvocationTargetException e) + { + throw new MBeanException((Exception) e.getCause(), + "The getter of " + field + + " threw an exception"); + } + } + try + { + return new CompositeDataSupport(cType, + (String[]) + names.toArray(new String[names.size()]), + values.toArray()); + } + catch (OpenDataException e) + { + throw (InternalError) (new InternalError("A problem occurred " + + "converting the value " + + "to a composite data " + + "structure.").initCause(e)); + } + } + + protected MBeanInfo getCachedMBeanInfo() + { + return (MBeanInfo) openInfo; + } + + /** + * Override this method so as to prevent the description of a constructor's + * parameter being @code{null}. Open MBeans can not have @code{null} descriptions, + * but one will occur as the names of parameters aren't stored for reflection. + * + * @param constructor the constructor whose parameter needs describing. + * @param parameter the parameter to be described. + * @param sequenceNo the number of the parameter to describe. + * @return a description of the constructor's parameter. + */ + protected String getDescription(MBeanConstructorInfo constructor, + MBeanParameterInfo parameter, + int sequenceNo) + { + String desc = parameter.getDescription(); + if (desc == null) + return "param" + sequenceNo; + else + return desc; + } + + /** + * Override this method so as to prevent the description of an operation's + * parameter being @code{null}. Open MBeans can not have @code{null} descriptions, + * but one will occur as the names of parameters aren't stored for reflection. + * + * @param operation the operation whose parameter needs describing. + * @param parameter the parameter to be described. + * @param sequenceNo the number of the parameter to describe. + * @return a description of the operation's parameter. + */ + protected String getDescription(MBeanOperationInfo operation, + MBeanParameterInfo parameter, + int sequenceNo) + { + String desc = parameter.getDescription(); + if (desc == null) + return "param" + sequenceNo; + else + return desc; + } + + /** + * Override this method so as to prevent the name of a constructor's + * parameter being @code{null}. Open MBeans can not have @code{null} names, + * but one will occur as the names of parameters aren't stored for reflection. + * + * @param constructor the constructor whose parameter needs a name. + * @param parameter the parameter to be named. + * @param sequenceNo the number of the parameter to name. + * @return a description of the constructor's parameter. + */ + protected String getParameterName(MBeanConstructorInfo constructor, + MBeanParameterInfo parameter, + int sequenceNo) + { + String name = parameter.getName(); + if (name == null) + return "param" + sequenceNo; + else + return name; + } + + /** + * Override this method so as to prevent the name of an operation's + * parameter being @code{null}. Open MBeans can not have @code{null} names, + * but one will occur as the names of parameters aren't stored for reflection. + * + * @param operation the operation whose parameter needs a name. + * @param parameter the parameter to be named. + * @param sequenceNo the number of the parameter to name. + * @return a description of the operation's parameter. + */ + protected String getParameterName(MBeanOperationInfo operation, + MBeanParameterInfo parameter, + int sequenceNo) + { + String name = parameter.getName(); + if (name == null) + return "param" + sequenceNo; + else + return name; + } + + public MBeanInfo getMBeanInfo() + { + super.getMBeanInfo(); + return getCachedMBeanInfo(); + } + + private OpenMBeanParameterInfo[] translateSignature(MBeanParameterInfo[] oldS) + throws OpenDataException + { + OpenMBeanParameterInfo[] sig = new OpenMBeanParameterInfoSupport[oldS.length]; + for (int a = 0; a < oldS.length; ++a) + { + OpenMBeanParameterInfo param = Translator.translate(oldS[a].getType()); + if (param.getMinValue() == null) + { + Object[] lv; + if (param.getLegalValues() == null) + lv = null; + else + lv = param.getLegalValues().toArray(); + sig[a] = new OpenMBeanParameterInfoSupport(oldS[a].getName(), + oldS[a].getDescription(), + ((OpenType) + param.getOpenType()), + param.getDefaultValue(), + lv); + } + else + sig[a] = new OpenMBeanParameterInfoSupport(oldS[a].getName(), + oldS[a].getDescription(), + ((OpenType) + param.getOpenType()), + param.getDefaultValue(), + ((Comparable) + param.getMinValue()), + ((Comparable) + param.getMaxValue())); + } + return sig; + } + + +} diff --git a/libjava/classpath/gnu/java/lang/management/ClassLoadingMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/ClassLoadingMXBeanImpl.java new file mode 100644 index 000000000..d98a39633 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/ClassLoadingMXBeanImpl.java @@ -0,0 +1,98 @@ +/* ClassLoadingMXBeanImpl.java - Implementation of a class loading bean + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.lang.management; + +import java.lang.management.ClassLoadingMXBean; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about the class loading + * behaviour of the current invocation of the virtual + * machine. Instances of this bean are obtained by calling + * {@link ManagementFactory#getClassLoadingMXBean()}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class ClassLoadingMXBeanImpl + extends BeanImpl + implements ClassLoadingMXBean +{ + + /** + * Constructs a new ClassLoadingMXBeanImpl. + * + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public ClassLoadingMXBeanImpl() + throws NotCompliantMBeanException + { + super(ClassLoadingMXBean.class); + } + + public int getLoadedClassCount() + { + return VMClassLoadingMXBeanImpl.getLoadedClassCount(); + } + + public long getTotalLoadedClassCount() + { + return getLoadedClassCount() + getUnloadedClassCount(); + } + + public long getUnloadedClassCount() + { + return VMClassLoadingMXBeanImpl.getUnloadedClassCount(); + } + + public boolean isVerbose() + { + return VMClassLoadingMXBeanImpl.isVerbose(); + } + + public void setVerbose(boolean verbose) + { + checkControlPermissions(); + VMClassLoadingMXBeanImpl.setVerbose(verbose); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/CompilationMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/CompilationMXBeanImpl.java new file mode 100644 index 000000000..1b77edf5a --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/CompilationMXBeanImpl.java @@ -0,0 +1,105 @@ +/* CompilationMXBeanImpl.java - Implementation of a compilation bean + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.lang.management; + +import gnu.classpath.SystemProperties; + +import java.lang.management.CompilationMXBean; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about the JIT + * compiler of the virtual machine, if one exists. + * Instances of this bean are obtained by calling + * {@link ManagementFactory#getCompilationMXBean()}, + * if this is the case. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class CompilationMXBeanImpl + extends BeanImpl + implements CompilationMXBean +{ + + /** + * Constant for compiler name. + */ + private static final String COMPILER_NAME = "gnu.java.compiler.name"; + + /** + * Constant for compilation time support. + */ + private static final String COMPILATION_TIME_SUPPORT = + "gnu.java.lang.management.CompilationTimeSupport"; + + /** + * Constructs a new CompilationMXBeanImpl. + * + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public CompilationMXBeanImpl() + throws NotCompliantMBeanException + { + super(CompilationMXBean.class); + } + + public String getName() + { + return SystemProperties.getProperty(COMPILER_NAME); + } + + public boolean isCompilationTimeMonitoringSupported() + { + return SystemProperties.getProperty(COMPILATION_TIME_SUPPORT) != null; + } + + public long getTotalCompilationTime() + { + if (isCompilationTimeMonitoringSupported()) + return VMCompilationMXBeanImpl.getTotalCompilationTime(); + else + throw new UnsupportedOperationException("Compilation time monitoring " + + "is not supported"); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/GarbageCollectorMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/GarbageCollectorMXBeanImpl.java new file mode 100644 index 000000000..7a2d762fa --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/GarbageCollectorMXBeanImpl.java @@ -0,0 +1,84 @@ +/* GarbageCollectorMXBeanImpl.java - Implementation of a GC bean + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.lang.management; + +import java.lang.management.GarbageCollectorMXBean; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about one of the garbage + * collectors used by the current invocation of the + * virtual machine. An instance of this bean for each garbage + * collector is obtained by calling + * {@link ManagementFactory#getGarbageCollectorMXBeans()}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class GarbageCollectorMXBeanImpl + extends MemoryManagerMXBeanImpl + implements GarbageCollectorMXBean +{ + + /** + * Constructs a new GarbageCollectorMXBeanImpl. + * + * @param name the name of the garbage collector this bean represents. + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public GarbageCollectorMXBeanImpl(String name) + throws NotCompliantMBeanException + { + super(name, GarbageCollectorMXBean.class); + } + + public long getCollectionCount() + { + return VMGarbageCollectorMXBeanImpl.getCollectionCount(name); + } + + public long getCollectionTime() + { + return VMGarbageCollectorMXBeanImpl.getCollectionTime(name); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/MemoryMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/MemoryMXBeanImpl.java new file mode 100644 index 000000000..10e6522f1 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/MemoryMXBeanImpl.java @@ -0,0 +1,281 @@ +/* MemoryMXBeanImpl.java - Implementation of a memory bean + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.lang.management; + +import gnu.javax.management.ListenerData; + +import java.lang.management.MemoryMXBean; +import java.lang.management.MemoryNotificationInfo; +import java.lang.management.MemoryUsage; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import javax.management.ListenerNotFoundException; +import javax.management.MBeanNotificationInfo; +import javax.management.NotCompliantMBeanException; +import javax.management.Notification; +import javax.management.NotificationEmitter; +import javax.management.NotificationFilter; +import javax.management.NotificationListener; + +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeDataSupport; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; + +/** + * Provides access to information about the memory + * management of the current invocation of the virtual + * machine. Instances of this bean are obtained by calling + * {@link ManagementFactory#getMemoryMXBean()}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class MemoryMXBeanImpl + extends BeanImpl + implements MemoryMXBean, NotificationEmitter +{ + + private List listeners; + + private long notificationCount; + + public static CompositeType notifType; + + public static CompositeType usageType; + + static + { + try + { + CompositeType usageType = + new CompositeType(MemoryUsage.class.getName(), + "Describes the usage levels of a pool", + new String[] { "init", "used", + "committed", "max" + }, + new String[] { "Initial level", + "Used level", + "Committed level", + "Maximum level" + }, + new OpenType[] { + SimpleType.LONG, SimpleType.LONG, + SimpleType.LONG, SimpleType.LONG + }); + CompositeType notifType = + new CompositeType(MemoryNotificationInfo.class.getName(), + "Provides the notification info on memory usage", + new String[] { "poolName", "usage", "count" }, + new String[] { "Name of the memory pool", + "Usage level of the memory pool", + "Number of times the threshold " + + "has been crossed" + }, + new OpenType[] { + SimpleType.STRING, usageType, SimpleType.LONG + }); + } + catch (OpenDataException e) + { + throw new IllegalStateException("Something went wrong in creating " + + "the composite data types.", e); + } + } + + /** + * Constructs a new MemoryMXBeanImpl. + * + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public MemoryMXBeanImpl() + throws NotCompliantMBeanException + { + super(MemoryMXBean.class); + listeners = new ArrayList(); + notificationCount = 0; + } + + public void gc() + { + System.gc(); + } + + public MemoryUsage getHeapMemoryUsage() + { + return VMMemoryMXBeanImpl.getHeapMemoryUsage(); + } + + public MemoryUsage getNonHeapMemoryUsage() + { + return VMMemoryMXBeanImpl.getNonHeapMemoryUsage(); + } + + public int getObjectPendingFinalizationCount() + { + return VMMemoryMXBeanImpl.getObjectPendingFinalizationCount(); + } + + public boolean isVerbose() + { + return VMMemoryMXBeanImpl.isVerbose(); + } + + public void setVerbose(boolean verbose) + { + checkControlPermissions(); + VMMemoryMXBeanImpl.setVerbose(verbose); + } + + public void addNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object passback) + { + if (listener == null) + throw new IllegalArgumentException("Null listener added to bean."); + listeners.add(new ListenerData(listener, filter, passback)); + } + + public MBeanNotificationInfo[] getNotificationInfo() + { + return new MBeanNotificationInfo[] + { + new MBeanNotificationInfo(new String[] + { + MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED, + MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED + }, + Notification.class.getName(), + "Memory Usage Notifications") + }; + } + + public void removeNotificationListener(NotificationListener listener) + throws ListenerNotFoundException + { + Iterator it = listeners.iterator(); + boolean foundOne = false; + while (it.hasNext()) + { + ListenerData data = (ListenerData) it.next(); + if (data.getListener() == listener) + { + it.remove(); + foundOne = true; + } + } + if (!foundOne) + throw new ListenerNotFoundException("The specified listener, " + listener + + "is not registered with this bean."); + } + + public void removeNotificationListener(NotificationListener listener, + NotificationFilter filter, + Object passback) + throws ListenerNotFoundException + { + if (!(listeners.remove(new ListenerData(listener, filter, passback)))) + { + throw new ListenerNotFoundException("The specified listener, " + listener + + " with filter " + filter + + "and passback " + passback + + ", is not registered with this bean."); + } + } + + void fireNotification(String type, String poolName, long init, long used, + long committed, long max, long count) + { + Notification notif = new Notification(type, this, notificationCount); + MemoryUsage usage = new MemoryUsage(init, used, committed, max); + CompositeData data; + try + { + data = new CompositeDataSupport(notifType, + new String[] { + "poolName", "usage", "count" + }, + new Object[] { + poolName, usage, Long.valueOf(count) + }); + } + catch (OpenDataException e) + { + throw new IllegalStateException("Something went wrong in creating " + + "the composite data instance.", e); + } + notif.setUserData(data); + Iterator it = listeners.iterator(); + while (it.hasNext()) + { + ListenerData ldata = (ListenerData) it.next(); + NotificationFilter filter = ldata.getFilter(); + if (filter == null || filter.isNotificationEnabled(notif)) + ldata.getListener().handleNotification(notif, ldata.getPassback()); + } + ++notificationCount; + } + + void fireThresholdExceededNotification(String poolName, long init, + long used, long committed, + long max, long count) + { + fireNotification(MemoryNotificationInfo.MEMORY_THRESHOLD_EXCEEDED, + poolName, init, used, committed, max, count); + } + + void fireCollectionThresholdExceededNotification(String poolName, + long init, + long used, + long committed, + long max, + long count) + { + fireNotification(MemoryNotificationInfo.MEMORY_COLLECTION_THRESHOLD_EXCEEDED, + poolName, init, used, committed, max, count); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/MemoryManagerMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/MemoryManagerMXBeanImpl.java new file mode 100644 index 000000000..51d0ed972 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/MemoryManagerMXBeanImpl.java @@ -0,0 +1,112 @@ +/* MemoryManagerMXBeanImpl.java - Implementation of a memory manager bean + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.lang.management; + +import java.lang.management.MemoryManagerMXBean; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about one of the memory + * managers used by the current invocation of the + * virtual machine. An instance of this bean for each memory + * manager is obtained by calling + * {@link ManagementFactory#getMemoryPoolMXBeans()}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class MemoryManagerMXBeanImpl + extends BeanImpl + implements MemoryManagerMXBean +{ + + /** + * The name of the memory manager. + */ + protected String name; + + /** + * Constructs a new MemoryManagerMXBeanImpl. + * + * @param name the name of the manager this bean represents. + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public MemoryManagerMXBeanImpl(String name) + throws NotCompliantMBeanException + { + this(name, MemoryManagerMXBean.class); + } + + /** + * Constructs a new MemoryManagerMXBeanImpl + * implementing the specified bean interface. + * + * @param name the name of the manager this bean represents. + * @param iface the bean interface being implemented. + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + protected MemoryManagerMXBeanImpl(String name, Class iface) + throws NotCompliantMBeanException + { + super(iface); + this.name = name; + } + + public String[] getMemoryPoolNames() + { + return VMMemoryManagerMXBeanImpl.getMemoryPoolNames(name); + } + + public String getName() + { + return name; + } + + public boolean isValid() + { + return VMMemoryManagerMXBeanImpl.isValid(name); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/MemoryPoolMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/MemoryPoolMXBeanImpl.java new file mode 100644 index 000000000..d92e6703f --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/MemoryPoolMXBeanImpl.java @@ -0,0 +1,226 @@ +/* MemoryPoolMXBeanImpl.java - Implementation of a memory pool bean + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.lang.management; + +import gnu.classpath.SystemProperties; + +import java.lang.management.MemoryPoolMXBean; +import java.lang.management.MemoryType; +import java.lang.management.MemoryUsage; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about one of the memory + * resources or pools used by the current invocation of the + * virtual machine. An instance of this bean for each memory + * pool is obtained by calling + * {@link ManagementFactory#getMemoryPoolMXBeans()}. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class MemoryPoolMXBeanImpl + extends BeanImpl + implements MemoryPoolMXBean +{ + + /** + * The name of the pool. + */ + private String name; + + /** + * Constant for collection usage threshold. + */ + private static final String COLLECTION_USAGE_THRESHOLD = + "gnu.java.lang.management.CollectionUsageThresholdSupport"; + + /** + * Constant for thread time support. + */ + private static final String USAGE_THRESHOLD = + "gnu.java.lang.management.UsageThresholdSupport"; + + /** + * Constructs a new MemoryPoolMXBeanImpl. + * + * @param name the name of the pool this bean represents. + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public MemoryPoolMXBeanImpl(String name) + throws NotCompliantMBeanException + { + super(MemoryPoolMXBean.class); + this.name = name; + } + + public MemoryUsage getCollectionUsage() + { + return VMMemoryPoolMXBeanImpl.getCollectionUsage(name); + } + + public long getCollectionUsageThreshold() + { + if (isCollectionUsageThresholdSupported()) + return VMMemoryPoolMXBeanImpl.getCollectionUsageThreshold(name); + else + throw new UnsupportedOperationException("A collection usage "+ + "threshold is not supported."); + } + + public long getCollectionUsageThresholdCount() + { + if (isCollectionUsageThresholdSupported()) + return VMMemoryPoolMXBeanImpl.getCollectionUsageThresholdCount(name); + else + throw new UnsupportedOperationException("A collection usage "+ + "threshold is not supported."); + } + + public String[] getMemoryManagerNames() + { + return VMMemoryPoolMXBeanImpl.getMemoryManagerNames(name); + } + + public String getName() + { + return name; + } + + public MemoryUsage getPeakUsage() + { + if (isValid()) + return VMMemoryPoolMXBeanImpl.getPeakUsage(name); + else + return null; + } + + public MemoryType getType() + { + return + MemoryType.valueOf(VMMemoryPoolMXBeanImpl.getType(name)); + } + + public MemoryUsage getUsage() + { + if (isValid()) + return VMMemoryPoolMXBeanImpl.getUsage(name); + else + return null; + } + + public long getUsageThreshold() + { + if (isUsageThresholdSupported()) + return VMMemoryPoolMXBeanImpl.getUsageThreshold(name); + else + throw new UnsupportedOperationException("A usage threshold " + + "is not supported."); + } + + public long getUsageThresholdCount() + { + if (isUsageThresholdSupported()) + return VMMemoryPoolMXBeanImpl.getUsageThresholdCount(name); + else + throw new UnsupportedOperationException("A usage threshold " + + "is not supported."); + } + + public boolean isCollectionUsageThresholdExceeded() + { + return getCollectionUsage().getUsed() >= getCollectionUsageThreshold(); + } + + public boolean isCollectionUsageThresholdSupported() + { + return SystemProperties.getProperty(COLLECTION_USAGE_THRESHOLD) != null; + } + + public boolean isUsageThresholdExceeded() + { + return getUsage().getUsed() >= getUsageThreshold(); + } + + public boolean isUsageThresholdSupported() + { + return SystemProperties.getProperty(USAGE_THRESHOLD) != null; + } + + public boolean isValid() + { + return VMMemoryPoolMXBeanImpl.isValid(name); + } + + public void resetPeakUsage() + { + checkControlPermissions(); + VMMemoryPoolMXBeanImpl.resetPeakUsage(name); + } + + public void setCollectionUsageThreshold(long threshold) + { + checkControlPermissions(); + if (threshold < 0) + throw new IllegalArgumentException("Threshold of " + threshold + + "is less than zero."); + if (isCollectionUsageThresholdSupported()) + VMMemoryPoolMXBeanImpl.setCollectionUsageThreshold(name, threshold); + else + throw new UnsupportedOperationException("A collection usage "+ + "threshold is not supported."); + } + + public void setUsageThreshold(long threshold) + { + checkControlPermissions(); + if (threshold < 0) + throw new IllegalArgumentException("Threshold of " + threshold + + "is less than zero."); + if (isUsageThresholdSupported()) + VMMemoryPoolMXBeanImpl.setUsageThreshold(name, threshold); + else + throw new UnsupportedOperationException("A usage threshold " + + "is not supported."); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/OperatingSystemMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/OperatingSystemMXBeanImpl.java new file mode 100644 index 000000000..7f5a9586c --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/OperatingSystemMXBeanImpl.java @@ -0,0 +1,95 @@ +/* OperatingSystemMXBeanImpl.java - Implementation of an operating system bean + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.lang.management; + +import java.lang.management.OperatingSystemMXBean; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about the underlying operating + * system. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class OperatingSystemMXBeanImpl + extends BeanImpl + implements OperatingSystemMXBean +{ + + /** + * Constructs a new OperatingSystemMXBeanImpl. + * + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public OperatingSystemMXBeanImpl() + throws NotCompliantMBeanException + { + super(OperatingSystemMXBean.class); + } + + public String getArch() + { + return System.getProperty("os.arch"); + } + + public int getAvailableProcessors() + { + return Runtime.getRuntime().availableProcessors(); + } + + public String getName() + { + return System.getProperty("os.name"); + } + + public double getSystemLoadAverage() + { + return VMOperatingSystemMXBeanImpl.getSystemLoadAverage(); + } + + public String getVersion() + { + return System.getProperty("os.version"); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/RuntimeMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/RuntimeMXBeanImpl.java new file mode 100644 index 000000000..8db943bb6 --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/RuntimeMXBeanImpl.java @@ -0,0 +1,197 @@ +/* RuntimeMXBeanImpl.java - Implementation of an runtime bean + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.lang.management; + +import gnu.classpath.SystemProperties; + +import java.lang.management.RuntimeMXBean; + +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about the virtual machine. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class RuntimeMXBeanImpl + extends BeanImpl + implements RuntimeMXBean +{ + + private static final String SUN_BOOT_CLASS_PATH = "sun.boot.class.path"; + private static final String JAVA_BOOT_CLASS_PATH = "java.boot.class.path"; + + private long startTime = -1; + + private String bootClassPath = null; + + private boolean bootClassPathSupported = true; + + /** + * Constructs a new RuntimeMXBeanImpl. + * + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public RuntimeMXBeanImpl() + throws NotCompliantMBeanException + { + super(RuntimeMXBean.class); + } + + public String getBootClassPath() + { + checkMonitorPermissions(); + if (isBootClassPathSupported()) + return bootClassPath; + else + throw + new UnsupportedOperationException("Retrieving the boot " + + "classpath is not supported."); + } + + public String getClassPath() + { + return System.getProperty("java.class.path"); + } + + public List getInputArguments() + { + checkMonitorPermissions(); + return Arrays.asList(VMRuntimeMXBeanImpl.getInputArguments()); + } + + public String getLibraryPath() + { + return System.getProperty("java.library.path"); + } + + public String getManagementSpecVersion() + { + return "1.0"; + } + + public String getName() + { + return VMRuntimeMXBeanImpl.getName(); + } + + public String getSpecName() + { + return System.getProperty("java.vm.specification.name"); + } + + public String getSpecVendor() + { + return System.getProperty("java.vm.specification.vendor"); + } + + public String getSpecVersion() + { + return System.getProperty("java.vm.specification.version"); + } + + public long getStartTime() + { + if (startTime == -1) + startTime = VMRuntimeMXBeanImpl.getStartTime(); + return startTime; + } + + public Map getSystemProperties() + { + Map map = new HashMap(); + Properties props = System.getProperties(); + Iterator entries = props.entrySet().iterator(); + while (entries.hasNext()) + { + Map.Entry next = (Map.Entry) entries.next(); + Object key = next.getKey(); + Object value = next.getValue(); + if (key instanceof String && + value instanceof String) + map.put(key, value); + } + return map; + } + + public long getUptime() + { + return new Date().getTime() - getStartTime(); + } + + public String getVmName() + { + return System.getProperty("java.vm.name"); + } + + public String getVmVendor() + { + return System.getProperty("java.vm.vendor"); + } + + public String getVmVersion() + { + return System.getProperty("java.vm.version"); + } + + public boolean isBootClassPathSupported() + { + if (bootClassPath == null) + { + bootClassPath = SystemProperties.getProperty(JAVA_BOOT_CLASS_PATH); + if (bootClassPath == null) + bootClassPath = SystemProperties.getProperty(SUN_BOOT_CLASS_PATH); + if (bootClassPath == null) + bootClassPathSupported = false; + } + return bootClassPathSupported; + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/ThreadMXBeanImpl.java b/libjava/classpath/gnu/java/lang/management/ThreadMXBeanImpl.java new file mode 100644 index 000000000..97040997b --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/ThreadMXBeanImpl.java @@ -0,0 +1,350 @@ +/* ThreadMXBeanImpl.java - Implementation of a thread bean + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.lang.management; + +import gnu.classpath.SystemProperties; + +import java.lang.management.ThreadInfo; +import java.lang.management.ThreadMXBean; + +import javax.management.NotCompliantMBeanException; + +/** + * Provides access to information about the threads + * of the virtual machine. An instance of this bean is + * obtained by calling + * {@link ManagementFactory#getThreadMXBean()}. + * See {@link java.lang.management.ThreadMXBean} for + * full documentation. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public final class ThreadMXBeanImpl + extends BeanImpl + implements ThreadMXBean +{ + + /** + * Constant for current thread time support. + */ + private static final String CURRENT_THREAD_TIME_SUPPORT = + "gnu.java.lang.management.CurrentThreadTimeSupport"; + + /** + * Constant for thread time support. + */ + private static final String THREAD_TIME_SUPPORT = + "gnu.java.lang.management.ThreadTimeSupport"; + + /** + * Constant for thread contention support. + */ + private static final String CONTENTION_SUPPORT = + "gnu.java.lang.management.ThreadContentionSupport"; + + /** + * Constant for initial value of thread time support. + */ + private static final String TIME_ENABLED = + "gnu.java.lang.management.ThreadTimeInitallyEnabled"; + + /** + * Constant for monitor usage monitoring support. + */ + private static final String MONITOR_SUPPORT = + "gnu.java.lang.management.MonitorUsageMonitoringSupport"; + + /** + * Constant for ownable synchronizer usage monitoring support. + */ + private static final String SYNCHRONIZER_SUPPORT = + "gnu.java.lang.management.OwnableSynchronizerUsageMonitoringSupport"; + + /** + * Flag to indicate whether time monitoring is enabled or not. + */ + private boolean timeEnabled; + + /** + * Flag to indicate whether contention monitoring is enabled or not. + */ + private boolean contentionEnabled; + + /** + * Default constructor to set up flag states. The + * VM has to specify whether time monitoring is initially + * enabled or not. + * + * @throws NotCompliantMBeanException if this class doesn't implement + * the interface or a method appears + * in the interface that doesn't comply + * with the naming conventions. + */ + public ThreadMXBeanImpl() + throws NotCompliantMBeanException + { + super(ThreadMXBean.class); + timeEnabled = Boolean.parseBoolean(SystemProperties.getProperty(TIME_ENABLED)); + contentionEnabled = false; + } + + public ThreadInfo[] dumpAllThreads(boolean lockedMonitors, + boolean lockedSynchronizers) + { + return getThreadInfo(getAllThreadIds(), lockedMonitors, + lockedSynchronizers); + } + + public long[] findDeadlockedThreads() + { + checkMonitorPermissions(); + if (!isSynchronizerUsageSupported()) + throw new UnsupportedOperationException("Ownable synchronizer usage " + + "monitoring is not provided " + + "by this VM."); + return VMThreadMXBeanImpl.findDeadlockedThreads(); + } + + public long[] findMonitorDeadlockedThreads() + { + checkMonitorPermissions(); + return VMThreadMXBeanImpl.findMonitorDeadlockedThreads(); + } + + public long[] getAllThreadIds() + { + checkMonitorPermissions(); + return VMThreadMXBeanImpl.getAllThreadIds(); + } + + public long getCurrentThreadCpuTime() + { + if (!isCurrentThreadCpuTimeSupported()) + throw new UnsupportedOperationException("Current thread CPU " + + "time not supported."); + if (!timeEnabled) + return -1; + return VMThreadMXBeanImpl.getCurrentThreadCpuTime(); + } + + public long getCurrentThreadUserTime() + { + if (!isCurrentThreadCpuTimeSupported()) + throw new UnsupportedOperationException("Current thread user " + + "time not supported."); + if (!timeEnabled) + return -1; + return VMThreadMXBeanImpl.getCurrentThreadUserTime(); + } + + public int getDaemonThreadCount() + { + return VMThreadMXBeanImpl.getDaemonThreadCount(); + } + + public int getPeakThreadCount() + { + return VMThreadMXBeanImpl.getPeakThreadCount(); + } + + public int getThreadCount() + { + return VMThreadMXBeanImpl.getThreadCount(); + } + + public long getThreadCpuTime(long id) + { + if (!isThreadCpuTimeSupported()) + throw new UnsupportedOperationException("Thread CPU time not " + + "supported."); + if (id <= 0) + throw new IllegalArgumentException("Invalid thread id: " + id); + if (!timeEnabled) + return -1; + return VMThreadMXBeanImpl.getThreadCpuTime(id); + } + + public ThreadInfo getThreadInfo(long id) + { + return getThreadInfo(id, 0); + } + + public ThreadInfo[] getThreadInfo(long[] ids) + { + return getThreadInfo(ids, 0); + } + + public ThreadInfo getThreadInfo(long id, int maxDepth) + { + checkMonitorPermissions(); + if (id <= 0) + throw new IllegalArgumentException("Invalid thread id: " + id); + if (maxDepth < 0) + throw new IllegalArgumentException("Invalid depth: " + maxDepth); + return VMThreadMXBeanImpl.getThreadInfoForId(id, maxDepth); + } + + public ThreadInfo[] getThreadInfo(long[] ids, int maxDepth) + { + checkMonitorPermissions(); + if (maxDepth < 0) + throw new IllegalArgumentException("Invalid depth: " + maxDepth); + ThreadInfo[] infos = new ThreadInfo[ids.length]; + for (int a = 0; a < ids.length; ++a) + { + if (ids[a] <= 0) + throw new IllegalArgumentException("Invalid thread id " + a + + ": " + ids[a]); + infos[a] = VMThreadMXBeanImpl.getThreadInfoForId(ids[a], maxDepth); + } + return infos; + } + + public ThreadInfo[] getThreadInfo(long[] ids, boolean lockedMonitors, + boolean lockedSynchronizers) + { + checkMonitorPermissions(); + if (lockedMonitors && !isObjectMonitorUsageSupported()) + throw new UnsupportedOperationException("Monitor usage monitoring is " + + "not provided by this VM."); + if (lockedSynchronizers && !isSynchronizerUsageSupported()) + throw new UnsupportedOperationException("Ownable synchronizer usage " + + "monitoring is not provided " + + "by this VM."); + ThreadInfo[] infos = getThreadInfo(ids, Integer.MAX_VALUE); + if (lockedMonitors) + for (ThreadInfo info : infos) + VMThreadMXBeanImpl.getMonitorInfo(info); + if (lockedSynchronizers) + for (ThreadInfo info : infos) + VMThreadMXBeanImpl.getLockInfo(info); + return infos; + } + + public long getThreadUserTime(long id) + { + if (!isThreadCpuTimeSupported()) + throw new UnsupportedOperationException("Thread user time not " + + "supported."); + if (id <= 0) + throw new IllegalArgumentException("Invalid thread id: " + id); + if (!timeEnabled) + return -1; + return VMThreadMXBeanImpl.getThreadUserTime(id); + } + + public long getTotalStartedThreadCount() + { + return VMThreadMXBeanImpl.getTotalStartedThreadCount(); + } + + public boolean isCurrentThreadCpuTimeSupported() + { + if (isThreadCpuTimeSupported()) + return true; + return SystemProperties.getProperty(CURRENT_THREAD_TIME_SUPPORT) != null; + } + + public boolean isObjectMonitorUsageSupported() + { + return SystemProperties.getProperty(MONITOR_SUPPORT) != null; + } + + public boolean isSynchronizerUsageSupported() + { + return SystemProperties.getProperty(SYNCHRONIZER_SUPPORT) != null; + } + + public boolean isThreadContentionMonitoringEnabled() + { + if (isThreadContentionMonitoringSupported()) + return contentionEnabled; + else + throw new UnsupportedOperationException("Contention monitoring " + + "not supported."); + } + + public boolean isThreadContentionMonitoringSupported() + { + return SystemProperties.getProperty(CONTENTION_SUPPORT) != null; + } + + public boolean isThreadCpuTimeEnabled() + { + if (isThreadCpuTimeSupported() || + isCurrentThreadCpuTimeSupported()) + return timeEnabled; + else + throw new UnsupportedOperationException("Thread time not " + + "supported."); + } + + public boolean isThreadCpuTimeSupported() + { + return SystemProperties.getProperty(THREAD_TIME_SUPPORT) != null; + } + + public void resetPeakThreadCount() + { + checkControlPermissions(); + VMThreadMXBeanImpl.resetPeakThreadCount(); + } + + public void setThreadContentionMonitoringEnabled(boolean enable) + { + checkControlPermissions(); + if (isThreadContentionMonitoringSupported()) + contentionEnabled = enable; + else + throw new UnsupportedOperationException("Contention monitoring " + + "not supported."); + } + + public void setThreadCpuTimeEnabled(boolean enable) + { + checkControlPermissions(); + if (isThreadCpuTimeSupported() || + isCurrentThreadCpuTimeSupported()) + timeEnabled = enable; + else + throw new UnsupportedOperationException("Thread time not " + + "supported."); + } + +} diff --git a/libjava/classpath/gnu/java/lang/management/package.html b/libjava/classpath/gnu/java/lang/management/package.html new file mode 100644 index 000000000..fc1bafc0c --- /dev/null +++ b/libjava/classpath/gnu/java/lang/management/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.lang.management + + +

GNU implementations of the Java system management beans.

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

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

+ + + diff --git a/libjava/classpath/gnu/java/locale/.cvsignore b/libjava/classpath/gnu/java/locale/.cvsignore new file mode 100644 index 000000000..d41ae8d81 --- /dev/null +++ b/libjava/classpath/gnu/java/locale/.cvsignore @@ -0,0 +1 @@ +LocaleData.java diff --git a/libjava/classpath/gnu/java/locale/LocaleHelper.java b/libjava/classpath/gnu/java/locale/LocaleHelper.java new file mode 100644 index 000000000..8b108768d --- /dev/null +++ b/libjava/classpath/gnu/java/locale/LocaleHelper.java @@ -0,0 +1,147 @@ +/* LocaleHelper.java -- helper routines for localization + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.locale; + +import java.text.Collator; +import java.util.Locale; + +/** + * This class provides common helper methods + * for handling localized data. + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * + * @see java.util.Locale + * @see java.util.ResourceBundle + */ +public class LocaleHelper +{ + /** + *

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

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

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

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

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

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

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

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

+ + + diff --git a/libjava/classpath/gnu/java/net/protocol/file/Connection.java b/libjava/classpath/gnu/java/net/protocol/file/Connection.java new file mode 100644 index 000000000..80155af0d --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/file/Connection.java @@ -0,0 +1,376 @@ +/* FileURLConnection.java -- URLConnection class for "file" protocol + Copyright (C) 1998, 1999, 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.net.protocol.file; + +import gnu.classpath.SystemProperties; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.FilePermission; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.OutputStreamWriter; +import java.io.Writer; +import java.net.ProtocolException; +import java.net.URL; +import java.net.URLConnection; +import java.security.Permission; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Locale; +import java.net.MalformedURLException; + +/** + * This subclass of java.net.URLConnection models a URLConnection via + * the "file" protocol. + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Nic Ferrier (nferrier@tapsellferrier.co.uk) + * @author Warren Levy (warrenl@cygnus.com) + */ +public class Connection extends URLConnection +{ + /** + * Default permission for a file + */ + private static final String DEFAULT_PERMISSION = "read"; + + private static class StaticData + { + /** + * HTTP-style DateFormat, used to format the last-modified header. + */ + static SimpleDateFormat dateFormat + = new SimpleDateFormat("EEE, dd MMM yyyy hh:mm:ss 'GMT'", + new Locale ("En", "Us", "Unix")); + + static String lineSeparator = + SystemProperties.getProperty("line.separator"); + } + + + /** + * This is a File object for this connection + */ + private File file; + + /** + * If a directory, contains a list of files in the directory. + */ + private byte[] directoryListing; + + /** + * InputStream if we are reading from the file + */ + private InputStream inputStream; + + /** + * OutputStream if we are writing to the file + */ + private OutputStream outputStream; + + /** + * FilePermission to read the file + */ + private FilePermission permission; + + /** + * Calls superclass constructor to initialize. + */ + public Connection(URL url) + { + super (url); + + permission = new FilePermission(getURL().getFile(), DEFAULT_PERMISSION); + } + + /** + * Unquote "%" + hex quotes characters + * + * @param str The string to unquote or null. + * + * @return The unquoted string or null if str was null. + * + * @exception MalformedURLException If the given string contains invalid + * escape sequences. + * + */ + public static String unquote(String str) throws MalformedURLException + { + if (str == null) + return null; + + final int MAX_BYTES_PER_UTF_8_CHAR = 3; + byte[] buf = new byte[str.length()*MAX_BYTES_PER_UTF_8_CHAR]; + int pos = 0; + for (int i = 0; i < str.length(); i++) + { + char c = str.charAt(i); + if (c == '%') + { + if (i + 2 >= str.length()) + throw new MalformedURLException(str + " : Invalid quoted character"); + int hi = Character.digit(str.charAt(++i), 16); + int lo = Character.digit(str.charAt(++i), 16); + if (lo < 0 || hi < 0) + throw new MalformedURLException(str + " : Invalid quoted character"); + buf[pos++] = (byte) (hi * 16 + lo); + } + else if (c > 127) { + try { + byte [] c_as_bytes = Character.toString(c).getBytes("utf-8"); + final int c_length = c_as_bytes.length; + System.arraycopy(c_as_bytes, 0, buf, pos, c_length); + pos += c_length; + } + catch (java.io.UnsupportedEncodingException x2) { + throw (Error) new InternalError().initCause(x2); + } + } + else + buf[pos++] = (byte) c; + } + try + { + return new String(buf, 0, pos, "utf-8"); + } + catch (java.io.UnsupportedEncodingException x2) + { + throw (Error) new InternalError().initCause(x2); + } + } + + /** + * "Connects" to the file by opening it. + */ + public void connect() throws IOException + { + // Call is ignored if already connected. + if (connected) + return; + + // If not connected, then file needs to be openned. + file = new File (unquote(getURL().getFile())); + + if (! file.isDirectory()) + { + if (doInput) + inputStream = new BufferedInputStream(new FileInputStream(file)); + + if (doOutput) + outputStream = new BufferedOutputStream(new FileOutputStream(file)); + } + else + { + if (doInput) + { + inputStream = new ByteArrayInputStream(getDirectoryListing()); + } + + if (doOutput) + throw new ProtocolException + ("file: protocol does not support output on directories"); + } + + connected = true; + } + + /** + * Populates the directoryListing field with a byte array + * containing a representation of the directory listing. + */ + byte[] getDirectoryListing() + throws IOException + { + if (directoryListing == null) + { + ByteArrayOutputStream sink = new ByteArrayOutputStream(); + // NB uses default character encoding for this system + Writer writer = new OutputStreamWriter(sink); + + String[] files = file.list(); + + for (int i = 0; i < files.length; i++) + { + writer.write(files[i]); + writer.write(StaticData.lineSeparator); + } + + directoryListing = sink.toByteArray(); + } + return directoryListing; + } + + /** + * Opens the file for reading and returns a stream for it. + * + * @return An InputStream for this connection. + * + * @exception IOException If an error occurs + */ + public InputStream getInputStream() + throws IOException + { + if (!doInput) + throw new ProtocolException("Can't open InputStream if doInput is false"); + + if (!connected) + connect(); + + return inputStream; + } + + /** + * Opens the file for writing and returns a stream for it. + * + * @return An OutputStream for this connection. + * + * @exception IOException If an error occurs. + */ + public OutputStream getOutputStream() + throws IOException + { + if (!doOutput) + throw new + ProtocolException("Can't open OutputStream if doOutput is false"); + + if (!connected) + connect(); + + return outputStream; + } + + /** + * Get the last modified time of the resource. + * + * @return the time since epoch that the resource was modified. + */ + public long getLastModified() + { + try + { + if (!connected) + connect(); + + return file.lastModified(); + } + catch (IOException e) + { + return -1; + } + } + + /** + * Get an http-style header field. Just handle a few common ones. + */ + public String getHeaderField(String field) + { + try + { + if (!connected) + connect(); + + if (field.equals("content-type")) + return guessContentTypeFromName(file.getName()); + else if (field.equals("content-length")) + { + if (file.isDirectory()) + { + return Integer.toString(getContentLength()); + } + return Long.toString(file.length()); + } + else if (field.equals("last-modified")) + { + synchronized (StaticData.dateFormat) + { + return StaticData.dateFormat.format( + new Date(file.lastModified())); + } + } + } + catch (IOException e) + { + // Fall through. + } + return null; + } + + /** + * Get the length of content. + * + * @return the length of the content. + */ + public int getContentLength() + { + try + { + if (!connected) + connect(); + + if (file.isDirectory()) + { + return getDirectoryListing().length; + } + return (int) file.length(); + } + catch (IOException e) + { + return -1; + } + } + + /** + * This method returns a Permission object representing the + * permissions required to access this URL. This method returns a + * java.io.FilePermission for the file's path with a read + * permission. + * + * @return A Permission object + */ + public Permission getPermission() throws IOException + { + return permission; + } +} diff --git a/libjava/classpath/gnu/java/net/protocol/file/Handler.java b/libjava/classpath/gnu/java/net/protocol/file/Handler.java new file mode 100644 index 000000000..58ebe4c46 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/file/Handler.java @@ -0,0 +1,91 @@ +/* Handler.java -- "file" protocol handler for java.net + Copyright (C) 1998, 1999, 2000, 2002, 2003, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.net.protocol.file; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +/** + * This is the protocol handler for the "file" protocol. + * It implements the abstract openConnection() method from + * URLStreamHandler by returning a new FileURLConnection object (from + * this package). All other methods are inherited + * + * @author Aaron M. Renn (arenn@urbanophile.com) + * @author Warren Levy (warrenl@cygnus.com) + */ +public class Handler extends URLStreamHandler +{ + /** + * A do nothing constructor + */ + public Handler() + { + } + + /** + * This method returs a new FileURLConnection for the specified URL + * + * @param url The URL to return a connection for + * + * @return The URLConnection + * + * @exception IOException If an error occurs + */ + protected URLConnection openConnection(URL url) throws IOException + { + // If a hostname is set, then we need to switch protocols to ftp + // in order to transfer this from the remote host. + String host = url.getHost(); + if ((host != null) && (! host.equals(""))) + { + // Reset the protocol (and implicitly the handler) for this URL. + // Then have the URL attempt the connection again, as it will + // get the changed handler the next time around. + // If the ftp protocol handler is not installed, an + // exception will be thrown from the new openConnection() call. + setURL (url, "ftp", url.getHost(), url.getPort(), url.getFile(), + url.getRef()); + return url.openConnection(); + } + + return new Connection(url); + } +} // class Handler diff --git a/libjava/classpath/gnu/java/net/protocol/file/package.html b/libjava/classpath/gnu/java/net/protocol/file/package.html new file mode 100644 index 000000000..cbce7413f --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/file/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.net.protocol.file + + +

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

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

+ +

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

+ +

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

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

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

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

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

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

+ +

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

+ +

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

+ + diff --git a/libjava/classpath/gnu/java/net/protocol/https/Handler.java b/libjava/classpath/gnu/java/net/protocol/https/Handler.java new file mode 100644 index 000000000..dbb619905 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/https/Handler.java @@ -0,0 +1,75 @@ +/* Handler.java -- + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.https; + +import gnu.java.net.protocol.http.HTTPConnection; +import gnu.java.net.protocol.http.HTTPURLConnection; + +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; + +/** + * An HTTPS URL stream handler. + * + * @author Chris Burdess (dog@gnu.org) + */ +public class Handler + extends URLStreamHandler +{ + + /** + * Returns the default HTTPS port (443). + */ + protected int getDefaultPort() + { + return HTTPConnection.HTTPS_PORT; + } + + /** + * Returns an HTTPURLConnection for the given URL. + */ + public URLConnection openConnection(URL url) + throws IOException + { + return new HTTPURLConnection(url); + } + +} diff --git a/libjava/classpath/gnu/java/net/protocol/jar/Connection.java b/libjava/classpath/gnu/java/net/protocol/jar/Connection.java new file mode 100644 index 000000000..85d27bfc9 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/jar/Connection.java @@ -0,0 +1,232 @@ +/* Connection - jar url connection for java.net + Copyright (C) 1999, 2002, 2003, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.jar; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.net.JarURLConnection; +import java.net.MalformedURLException; +import java.net.ProtocolException; +import java.net.URL; +import java.net.URLConnection; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.Hashtable; +import java.util.Locale; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.zip.ZipFile; + +/** + * This subclass of java.net.JarURLConnection models a URLConnection via + * the "jar" protocol. + * + * @author Kresten Krab Thorup (krab@gnu.org) + */ +public final class Connection extends JarURLConnection +{ + /** + * HTTP-style DateFormat, used to format the last-modified header. + * Lazy initialized since jar files are used during bootstrapping. + */ + private static SimpleDateFormat dateFormat; + + private JarFile jar_file; + private JarEntry jar_entry; + private URL jar_url; + + public static class JarFileCache + { + private static Hashtable cache + = new Hashtable(); + private static final int READBUFSIZE = 4*1024; + + public static synchronized JarFile get (URL url, boolean useCaches) + throws IOException + { + JarFile jf; + if (useCaches) + { + jf = cache.get (url); + if (jf != null) + return jf; + } + + if ("file".equals (url.getProtocol())) + { + String fn = url.getFile(); + fn = gnu.java.net.protocol.file.Connection.unquote(fn); + File f = new File (fn); + jf = new JarFile (f, true, ZipFile.OPEN_READ); + } + else + { + URLConnection urlconn = url.openConnection(); + InputStream is = urlconn.getInputStream(); + byte[] buf = new byte [READBUFSIZE]; + File f = File.createTempFile ("cache", "jar"); + FileOutputStream fos = new FileOutputStream (f); + int len = 0; + + while ((len = is.read (buf)) != -1) + { + fos.write (buf, 0, len); + } + + fos.close(); + // Always verify the Manifest, open read only and delete when done. + jf = new JarFile (f, true, + ZipFile.OPEN_READ | ZipFile.OPEN_DELETE); + } + + if (useCaches) + cache.put (url, jf); + + return jf; + } + } + + protected Connection(URL url) + throws MalformedURLException + { + super(url); + } + + public synchronized void connect() throws IOException + { + // Call is ignored if already connected. + if (connected) + return; + + jar_url = getJarFileURL(); + jar_file = JarFileCache.get (jar_url, useCaches); + String entry_name = getEntryName(); + + if (entry_name != null + && !entry_name.equals ("")) + { + jar_entry = (JarEntry) jar_file.getEntry (entry_name); + + if(jar_entry == null) + throw new FileNotFoundException("No entry for " + entry_name + " exists."); + } + + connected = true; + } + + public InputStream getInputStream() throws IOException + { + if (!connected) + connect(); + + if (! doInput) + throw new ProtocolException("Can't open InputStream if doInput is false"); + + return jar_file.getInputStream (jar_entry); + } + + public synchronized JarFile getJarFile() throws IOException + { + if (!connected) + connect(); + + if (! doInput) + throw new ProtocolException("Can't open JarFile if doInput is false"); + + return jar_file; + } + + public String getHeaderField(String field) + { + try + { + if (!connected) + connect(); + + if (field.equals("content-type")) + return guessContentTypeFromName(getJarEntry().getName()); + else if (field.equals("content-length")) + return Long.toString(getJarEntry().getSize()); + else if (field.equals("last-modified")) + { + // Both creating and manipulating dateFormat need synchronization. + synchronized (Connection.class) + { + if (dateFormat == null) + dateFormat = new SimpleDateFormat + ("EEE, dd MMM yyyy hh:mm:ss 'GMT'", + new Locale ("En", "Us", "Unix")); + + return dateFormat.format(new Date(getJarEntry().getTime())); + } + } + } + catch (IOException e) + { + // Fall through. + } + return null; + } + + public int getContentLength() + { + if (!connected) + return -1; + + return (int) jar_entry.getSize(); + } + + public long getLastModified() + { + if (!connected) + return -1; + + try + { + return getJarEntry().getTime(); + } + catch (IOException e) + { + return -1; + } + } +} diff --git a/libjava/classpath/gnu/java/net/protocol/jar/Handler.java b/libjava/classpath/gnu/java/net/protocol/jar/Handler.java new file mode 100644 index 000000000..7d6103e93 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/jar/Handler.java @@ -0,0 +1,217 @@ +/* gnu.java.net.protocol.jar.Handler - jar protocol handler for java.net + Copyright (C) 1999, 2002, 2003, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.net.protocol.jar; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.net.URLParseError; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.net.URLConnection; +import java.net.URLStreamHandler; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.StringTokenizer; + +/** + * @author Kresten Krab Thorup (krab@gnu.org) + */ +public class Handler extends URLStreamHandler +{ + /** + * A do nothing constructor + */ + public Handler() + { + } + + /** + * This method returs a new JarURLConnection for the specified URL + * + * @param url The URL to return a connection for + * + * @return The URLConnection + * + * @exception IOException If an error occurs + */ + protected URLConnection openConnection(URL url) throws IOException + { + return new Connection(url); + } + + /** + * This method overrides URLStreamHandler's for parsing url of protocol "jar" + * + * @param url The URL object in which to store the results + * @param url_string The String-ized URL to parse + * @param start The position in the string to start scanning from + * @param end The position in the string to stop scanning + */ + protected void parseURL (URL url, String url_string, int start, int end) + { + // This method does not throw an exception or return a value. Thus our + // strategy when we encounter an error in parsing is to return without + // doing anything. + String file = url.getFile(); + + if (!file.equals("")) + { //has context url + url_string = url_string.substring (start, end); + if (url_string.startsWith("/")) + { //url string is an absolute path + int idx = file.lastIndexOf ("!/"); + + if (idx < 0) + throw new URLParseError("no !/ in spec"); + + file = file.substring (0, idx + 1) + url_string; + } + else if (url_string.length() > 0) + { + int idx = file.lastIndexOf ("/"); + if (idx == -1) //context path is weird + file = "/" + url_string; + else if (idx == (file.length() - 1)) + //just concatenate two parts + file = file + url_string; + else + // according to Java API Documentation, here is a little different + // with URLStreamHandler.parseURL + // but JDK seems doesn't handle it well + file = file.substring(0, idx + 1) + url_string; + } + + setURL (url, "jar", url.getHost(), url.getPort(), flat(file), null); + return; + } + + // Bunches of things should be true. Make sure. + if (end < start) + return; + if (end - start < 2) + return; + if (start > url_string.length()) + return; + + // Skip remains of protocol + url_string = url_string.substring (start, end); + + int jar_stop; + if ((jar_stop = url_string.indexOf("!/")) < 0) + throw new URLParseError("no !/ in spec"); + + try + { + new URL(url_string.substring (0, jar_stop)); + } + catch (MalformedURLException e) + { + throw new URLParseError("invalid inner URL: " + e.getMessage()); + } + + if (!url.getProtocol().equals ("jar") ) + throw new URLParseError("unexpected protocol " + url.getProtocol()); + + setURL (url, "jar", url.getHost(), url.getPort(), url_string, null); + } + + /** + * Makes the given jar url string 'flat' by removing any . and .. from + * jar file path because ZipFile entries can only handle flat paths. + * Inside jar files '/' is always the path separator. + */ + private static String flat(String url_string) + { + int jar_stop = url_string.indexOf("!/"); + String jar_path = url_string.substring(jar_stop + 1, url_string.length()); + + if (jar_path.indexOf("/.") < 0) + return url_string; + + ArrayList tokens = new ArrayList(); + StringTokenizer st = new StringTokenizer(jar_path, "/"); + while (st.hasMoreTokens()) + { + String token = st.nextToken(); + if (token.equals(".")) + continue; + else if (token.equals("..")) + { + if (! tokens.isEmpty()) + tokens.remove(tokens.size() - 1); + } + else + tokens.add(token); + } + + CPStringBuilder path = new CPStringBuilder(url_string.length()); + path.append(url_string.substring(0, jar_stop + 1)); + + Iterator it = tokens.iterator(); + while (it.hasNext()) + path.append('/').append(it.next()); + + return path.toString(); + } + + /** + * This method converts a Jar URL object into a String. + * + * @param url The URL object to convert + */ + protected String toExternalForm (URL url) + { + String file = url.getFile(); + String ref = url.getRef(); + + // return "jar:" + file; + // Performance!!: + // Do the concatenation manually to avoid resize StringBuffer's + // internal buffer. The length of ref is not taken into consideration + // as it's a rare path. + CPStringBuilder sb = new CPStringBuilder (file.length() + 5); + sb.append ("jar:"); + sb.append (file); + if (ref != null) + sb.append('#').append(ref); + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/java/net/protocol/jar/package.html b/libjava/classpath/gnu/java/net/protocol/jar/package.html new file mode 100644 index 000000000..dcd263d59 --- /dev/null +++ b/libjava/classpath/gnu/java/net/protocol/jar/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.net.protocol.jar + + +

+ + + diff --git a/libjava/classpath/gnu/java/nio/ChannelInputStream.java b/libjava/classpath/gnu/java/nio/ChannelInputStream.java new file mode 100644 index 000000000..5cad678c6 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/ChannelInputStream.java @@ -0,0 +1,89 @@ +/* ChannelInputStream.java -- + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.nio; + +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.channels.IllegalBlockingModeException; +import java.nio.channels.ReadableByteChannel; +import java.nio.channels.SelectableChannel; + +/** + * @author Michael Koch + */ +public final class ChannelInputStream extends InputStream +{ + private ReadableByteChannel ch; + + public ChannelInputStream (ReadableByteChannel ch) + { + super(); + + this.ch = ch; + } + + public int read(byte[] buf, int off, int len) throws IOException + { + if (ch instanceof SelectableChannel + && (! ((SelectableChannel) ch).isBlocking())) + throw new IllegalBlockingModeException(); + + ByteBuffer b = ByteBuffer.wrap(buf, off, len); + return ch.read(b); + } + + public int read() throws IOException + { + if (ch instanceof SelectableChannel + && (! ((SelectableChannel) ch).isBlocking())) + throw new IllegalBlockingModeException(); + + ByteBuffer buffer = ByteBuffer.allocate(1); + int result = ch.read(buffer); + + if (result == -1) + return -1; + + if (result == 0) + throw new IOException("Could not read from channel"); + + return buffer.get(0) & 0xff; + } +} diff --git a/libjava/classpath/gnu/java/nio/ChannelOutputStream.java b/libjava/classpath/gnu/java/nio/ChannelOutputStream.java new file mode 100644 index 000000000..606f3775d --- /dev/null +++ b/libjava/classpath/gnu/java/nio/ChannelOutputStream.java @@ -0,0 +1,67 @@ +/* ChannelOutputStream.java -- + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.nio; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.channels.WritableByteChannel; + +/** + * @author Michael Koch + */ +public final class ChannelOutputStream extends OutputStream +{ + private WritableByteChannel ch; + + public ChannelOutputStream (WritableByteChannel ch) + { + super(); + + this.ch = ch; + } + + public void write (int value) throws IOException + { + ByteBuffer buffer = ByteBuffer.allocate (1); + buffer.put ((byte) (value & 0xff)); + buffer.flip(); + ch.write (buffer); + } +} diff --git a/libjava/classpath/gnu/java/nio/ChannelReader.java b/libjava/classpath/gnu/java/nio/ChannelReader.java new file mode 100644 index 000000000..3c1456a36 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/ChannelReader.java @@ -0,0 +1,217 @@ +/* ChannelReader.java -- + Copyright (C) 2005 Free Software Foundation, Inc. + + This file is part of GNU Classpath. + + GNU Classpath is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + GNU Classpath is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with GNU Classpath; see the file COPYING. If not, write to the + Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + 02110-1301 USA. + + Linking this library statically or dynamically with other modules is + making a combined work based on this library. Thus, the terms and + conditions of the GNU General Public License cover the whole + combination. + + As a special exception, the copyright holders of this library give you + permission to link this library with independent modules to produce an + executable, regardless of the license terms of these independent + modules, and to copy and distribute the resulting executable under + terms of your choice, provided that you also meet, for each linked + independent module, the terms and conditions of the license of that + module. An independent module is a module which is not derived from + or based on this library. If you modify this library, you may extend + this exception to your version of the library, but you are not + obligated to do so. If you do not wish to do so, delete this + exception statement from your version. */ + + +package gnu.java.nio; + +import java.io.IOException; +import java.io.Reader; +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.channels.ReadableByteChannel; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; +import java.nio.charset.CodingErrorAction; + +/** + * A Reader implementation that works using a ReadableByteChannel and a + * CharsetDecoder. + * + *

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

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

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

The lookup is therefore case-insensitive.

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

All names are converted to lower-case

. + * + * @param cs + */ + private void addCharset (Charset cs) + { + String canonicalName = cs.name().toLowerCase(); + charsets.put (canonicalName, cs); + + /* Adds a mapping between the canonical name + * itself making a lookup using that name + * no special case. + */ + canonicalNames.put(canonicalName, canonicalName); + + for (Iterator i = cs.aliases ().iterator (); i.hasNext (); ) + canonicalNames.put (((String) i.next()).toLowerCase(), canonicalName); + } + + public static synchronized Provider provider () + { + // The default provider is safe to instantiate. + if (singleton == null) + singleton = AccessController.doPrivileged + (new PrivilegedAction() + { + public Provider run() + { + return new Provider(); + } + }); + return singleton; + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/US_ASCII.java b/libjava/classpath/gnu/java/nio/charset/US_ASCII.java new file mode 100644 index 000000000..373b37a1f --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/US_ASCII.java @@ -0,0 +1,162 @@ +/* US_ASCII.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +/** + * US-ASCII charset. + * + * @author Jesse Rosenstock + * @modified Ian Rogers + */ +final class US_ASCII extends Charset +{ + US_ASCII () + { + /* Canonical charset name chosen according to: + * http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html + */ + super ("US-ASCII", new String[] { + /* These names are provided by + * http://www.iana.org/assignments/character-sets + */ + "iso-ir-6", + "ANSI_X3.4-1986", + "ISO_646.irv:1991", + "ASCII", + "ISO646-US", + "ASCII", + "us", + "IBM367", + "cp367", + "csASCII", + /* These names are provided by + * http://oss.software.ibm.com/cgi-bin/icu/convexp?s=ALL + */ + "ANSI_X3.4-1968", "iso_646.irv:1983", "ascii7", "646", + "windows-20127" + }); + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII; + } + + public CharsetDecoder newDecoder () + { + return new Decoder (this); + } + + public CharsetEncoder newEncoder () + { + return new Encoder (this); + } + + private static final class Decoder extends CharsetDecoder + { + /** Helper to decode loops */ + private static final ByteDecodeLoopHelper helper = new ByteDecodeLoopHelper() + { + protected boolean isMappable(byte b) + { + return b >= 0; + } + protected char mapToChar(byte b) + { + return (char)b; + } + }; + + // Package-private to avoid a trampoline constructor. + Decoder (Charset cs) + { + super (cs, 1.0f, 1.0f); + } + + protected CoderResult decodeLoop (ByteBuffer in, CharBuffer out) + { + return helper.decodeLoop(in, out); + } + } + + private static final class Encoder extends CharsetEncoder + { + /** Helper to encode loops */ + private static final ByteEncodeLoopHelper helper = new ByteEncodeLoopHelper() + { + protected boolean isMappable(char c) + { + return c <= 0x7f; + } + protected byte mapToByte(char c) + { + return (byte)c; + } + }; + // Package-private to avoid a trampoline constructor. + Encoder (Charset cs) + { + super (cs, 1.0f, 1.0f); + } + + public boolean canEncode(char c) + { + return c <= 0x7f; + } + + public boolean canEncode(CharSequence cs) + { + for (int i = 0; i < cs.length(); ++i) + if (! canEncode(cs.charAt(i))) + return false; + return true; + } + + protected CoderResult encodeLoop (CharBuffer in, ByteBuffer out) + { + return helper.encodeLoop(in, out); + } + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16.java b/libjava/classpath/gnu/java/nio/charset/UTF_16.java new file mode 100644 index 000000000..d91b15a7f --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16.java @@ -0,0 +1,80 @@ +/* UTF_16.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.nio.charset; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; + +/** + * UTF-16 charset. + * + * @author Jesse Rosenstock + */ +final class UTF_16 extends Charset +{ + UTF_16 () + { + super ("UTF-16", new String[] { + // witnessed by the internet + "UTF16", + /* These names are provided by + * http://oss.software.ibm.com/cgi-bin/icu/convexp?s=ALL + */ + "ISO-10646-UCS-2", "unicode", "csUnicode", "ucs-2", "UnicodeBig" + }); + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII || cs instanceof ISO_8859_1 + || cs instanceof UTF_8 || cs instanceof UTF_16BE + || cs instanceof UTF_16LE || cs instanceof UTF_16; + } + + public CharsetDecoder newDecoder () + { + return new UTF_16Decoder (this, UTF_16Decoder.UNKNOWN_ENDIAN); + } + + public CharsetEncoder newEncoder () + { + return new UTF_16Encoder (this, UTF_16Encoder.BIG_ENDIAN, true); + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16BE.java b/libjava/classpath/gnu/java/nio/charset/UTF_16BE.java new file mode 100644 index 000000000..1299b015e --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16BE.java @@ -0,0 +1,84 @@ +/* UTF_16BE.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.nio.charset; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; + +/** + * UTF-16BE charset. + * + * @author Jesse Rosenstock + */ +final class UTF_16BE extends Charset +{ + UTF_16BE () + { + super ("UTF-16BE", new String[] { + // witnessed by the internet + "UTF16BE", + /* These names are provided by + * http://oss.software.ibm.com/cgi-bin/icu/convexp?s=ALL + */ + "x-utf-16be", "ibm-1200", "ibm-1201", "ibm-5297", + "ibm-13488", "ibm-17584", "windows-1201", "cp1200", "cp1201", + "UTF16_BigEndian", + // see http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html + "UnicodeBigUnmarked" + }); + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII || cs instanceof ISO_8859_1 + || cs instanceof UTF_8 || cs instanceof UTF_16BE + || cs instanceof UTF_16LE || cs instanceof UTF_16; + } + + public CharsetDecoder newDecoder () + { + return new UTF_16Decoder (this, UTF_16Decoder.BIG_ENDIAN); + } + + public CharsetEncoder newEncoder () + { + return new UTF_16Encoder (this, UTF_16Encoder.BIG_ENDIAN, false); + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16Decoder.java b/libjava/classpath/gnu/java/nio/charset/UTF_16Decoder.java new file mode 100644 index 000000000..e078a6919 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16Decoder.java @@ -0,0 +1,167 @@ +/* UTF_16Decoder.java -- + Copyright (C) 2002, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; + +/** + * Decoder for UTF-16, UTF-15LE, and UTF-16BE. + * + * @author Jesse Rosenstock + */ +final class UTF_16Decoder extends CharsetDecoder +{ + // byte orders + static final int BIG_ENDIAN = 0; + static final int LITTLE_ENDIAN = 1; + static final int UNKNOWN_ENDIAN = 2; + static final int MAYBE_BIG_ENDIAN = 3; + static final int MAYBE_LITTLE_ENDIAN = 4; + + private static final char BYTE_ORDER_MARK = 0xFEFF; + private static final char REVERSED_BYTE_ORDER_MARK = 0xFFFE; + + private final int originalByteOrder; + private int byteOrder; + + UTF_16Decoder (Charset cs, int byteOrder) + { + super (cs, 0.5f, 1.0f); + this.originalByteOrder = byteOrder; + this.byteOrder = byteOrder; + } + + protected CoderResult decodeLoop (ByteBuffer in, CharBuffer out) + { + // TODO: Optimize this in the case in.hasArray() / out.hasArray() + + int inPos = in.position (); + try + { + while (in.remaining () >= 2) + { + byte b1 = in.get (); + byte b2 = in.get (); + + // handle byte order mark + if (byteOrder == UNKNOWN_ENDIAN || + byteOrder == MAYBE_BIG_ENDIAN || + byteOrder == MAYBE_LITTLE_ENDIAN) + { + char c = (char) (((b1 & 0xFF) << 8) | (b2 & 0xFF)); + if (c == BYTE_ORDER_MARK) + { + if (byteOrder == MAYBE_LITTLE_ENDIAN) + { + return CoderResult.malformedForLength (2); + } + byteOrder = BIG_ENDIAN; + inPos += 2; + continue; + } + else if (c == REVERSED_BYTE_ORDER_MARK) + { + if (byteOrder == MAYBE_BIG_ENDIAN) + { + return CoderResult.malformedForLength (2); + } + byteOrder = LITTLE_ENDIAN; + inPos += 2; + continue; + } + else + { + // assume big or little endian, do not consume bytes, + // continue with normal processing + byteOrder = (byteOrder == MAYBE_LITTLE_ENDIAN ? + LITTLE_ENDIAN : BIG_ENDIAN); + } + } + + // FIXME: Change so you only do a single comparison here. + char c = (byteOrder == BIG_ENDIAN + ? (char) (((b1 & 0xFF) << 8) | (b2 & 0xFF)) + : (char) (((b2 & 0xFF) << 8) | (b1 & 0xFF))); + + if (0xD800 <= c && c <= 0xDFFF) + { + // c is a surrogate + + // make sure c is a high surrogate + if (c > 0xDBFF) + return CoderResult.malformedForLength (2); + if (in.remaining () < 2) + return CoderResult.UNDERFLOW; + byte b3 = in.get (); + byte b4 = in.get (); + char d = (byteOrder == BIG_ENDIAN + ? (char) (((b3 & 0xFF) << 8) | (b4 & 0xFF)) + : (char) (((b4 & 0xFF) << 8) | (b3 & 0xFF))); + // make sure d is a low surrogate + if (d < 0xDC00 || d > 0xDFFF) + return CoderResult.malformedForLength (2); + out.put (c); + out.put (d); + inPos += 4; + } + else + { + if (!out.hasRemaining ()) + return CoderResult.UNDERFLOW; + out.put (c); + inPos += 2; + } + } + + return CoderResult.UNDERFLOW; + } + finally + { + in.position (inPos); + } + } + + protected void implReset () + { + byteOrder = originalByteOrder; + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16Encoder.java b/libjava/classpath/gnu/java/nio/charset/UTF_16Encoder.java new file mode 100644 index 000000000..5283be491 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16Encoder.java @@ -0,0 +1,145 @@ +/* UTF_16Encoder.java -- + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +/** + * Encoder for UTF-16, UTF-15LE, and UTF-16BE. + * + * @author Jesse Rosenstock + */ +final class UTF_16Encoder extends CharsetEncoder +{ + // byte orders + static final int BIG_ENDIAN = 0; + static final int LITTLE_ENDIAN = 1; + + private static final char BYTE_ORDER_MARK = 0xFEFF; + + private final ByteOrder byteOrder; + private final boolean useByteOrderMark; + private boolean needsByteOrderMark; + + UTF_16Encoder (Charset cs, int byteOrder, boolean useByteOrderMark) + { + super (cs, 2.0f, + useByteOrderMark ? 4.0f : 2.0f, + byteOrder == BIG_ENDIAN + ? new byte[] { (byte) 0xFF, (byte) 0xFD } + : new byte[] { (byte) 0xFD, (byte) 0xFF }); + this.byteOrder = (byteOrder == BIG_ENDIAN) ? + ByteOrder.BIG_ENDIAN : ByteOrder.LITTLE_ENDIAN; + this.useByteOrderMark = useByteOrderMark; + this.needsByteOrderMark = useByteOrderMark; + } + + protected CoderResult encodeLoop (CharBuffer in, ByteBuffer out) + { + // TODO: Optimize this in the case in.hasArray() / out.hasArray() + + ByteOrder originalBO = out.order(); + out.order(byteOrder); + + if (needsByteOrderMark) + { + if (out.remaining () < 2) + { + out.order(originalBO); + return CoderResult.OVERFLOW; + } + out.putChar (BYTE_ORDER_MARK); + needsByteOrderMark = false; + } + + int inPos = in.position (); + try + { + while (in.hasRemaining ()) + { + char c = in.get (); + if (0xD800 <= c && c <= 0xDFFF) + { + // c is a surrogate + + // make sure c is a high surrogate + if (c > 0xDBFF) + return CoderResult.malformedForLength (1); + if (in.remaining () < 1) + return CoderResult.UNDERFLOW; + char d = in.get (); + // make sure d is a low surrogate + if (d < 0xDC00 || d > 0xDFFF) + return CoderResult.malformedForLength (1); + out.putChar (c); + out.putChar (d); + inPos += 2; + } + else + { + if (out.remaining () < 2) + { + out.order(originalBO); + return CoderResult.OVERFLOW; + } + out.putChar (c); + inPos++; + } + } + out.order(originalBO); + return CoderResult.UNDERFLOW; + } + finally + { + in.position (inPos); + } + } + + protected void implReset () + { + needsByteOrderMark = useByteOrderMark; + } + + // TODO: override canEncode(char) and canEncode(CharSequence) + // for performance +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_16LE.java b/libjava/classpath/gnu/java/nio/charset/UTF_16LE.java new file mode 100644 index 000000000..bede38aa8 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_16LE.java @@ -0,0 +1,83 @@ +/* UTF_16LE.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.nio.charset; + +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; + +/** + * UTF-16LE charset. + * + * @author Jesse Rosenstock + */ +final class UTF_16LE extends Charset +{ + UTF_16LE () + { + super ("UTF-16LE", new String[] { + // witnessed by the internet + "UTF16LE", + /* These names are provided by + * http://oss.software.ibm.com/cgi-bin/icu/convexp?s=ALL + */ + "x-utf-16le", "ibm-1202", "ibm-13490", "ibm-17586", + "UTF16_LittleEndian", + // see http://java.sun.com/j2se/1.5.0/docs/guide/intl/encoding.doc.html + "UnicodeLittleUnmarked" + }); + } + + public boolean contains (Charset cs) + { + return cs instanceof US_ASCII || cs instanceof ISO_8859_1 + || cs instanceof UTF_8 || cs instanceof UTF_16BE + || cs instanceof UTF_16LE || cs instanceof UTF_16; + } + + public CharsetDecoder newDecoder () + { + return new UTF_16Decoder (this, UTF_16Decoder.LITTLE_ENDIAN); + } + + public CharsetEncoder newEncoder () + { + return new UTF_16Encoder (this, UTF_16Encoder.LITTLE_ENDIAN, false); + } +} diff --git a/libjava/classpath/gnu/java/nio/charset/UTF_8.java b/libjava/classpath/gnu/java/nio/charset/UTF_8.java new file mode 100644 index 000000000..0423efe51 --- /dev/null +++ b/libjava/classpath/gnu/java/nio/charset/UTF_8.java @@ -0,0 +1,311 @@ +/* UTF_8.java -- + Copyright (C) 2002, 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.nio.charset; + +import java.nio.ByteBuffer; +import java.nio.CharBuffer; +import java.nio.charset.Charset; +import java.nio.charset.CharsetDecoder; +import java.nio.charset.CharsetEncoder; +import java.nio.charset.CoderResult; + +/** + * UTF-8 charset. + * + *

UTF-8 references: + *

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

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

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

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

+ + + diff --git a/libjava/classpath/gnu/java/rmi/registry/RegistryImpl.java b/libjava/classpath/gnu/java/rmi/registry/RegistryImpl.java new file mode 100644 index 000000000..acdd463b1 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/registry/RegistryImpl.java @@ -0,0 +1,154 @@ +/* RegistryImpl.java -- + Copyright (c) 1996, 1997, 1998, 1999, 2002, 2005, 2008, 2009, 2010, 2011 + Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.rmi.registry; + +import gnu.java.rmi.server.UnicastServerRef; + +import java.rmi.AccessException; +import java.rmi.AlreadyBoundException; +import java.rmi.NotBoundException; +import java.rmi.Remote; +import java.rmi.RemoteException; +import java.rmi.registry.LocateRegistry; +import java.rmi.registry.Registry; +import java.rmi.server.ObjID; +import java.rmi.server.RMIClientSocketFactory; +import java.rmi.server.RMIServerSocketFactory; +import java.rmi.server.RMISocketFactory; +import java.rmi.server.UnicastRemoteObject; +import java.util.Enumeration; +import java.util.Hashtable; + +public class RegistryImpl + extends UnicastRemoteObject implements Registry { + +private Hashtable bindings = new Hashtable(); + +public RegistryImpl(int port) throws RemoteException { + this(port, RMISocketFactory.getSocketFactory(), RMISocketFactory.getSocketFactory()); +} + +public RegistryImpl(int port, RMIClientSocketFactory cf, RMIServerSocketFactory sf) throws RemoteException { + super(new UnicastServerRef(new ObjID(ObjID.REGISTRY_ID), port, sf)); + // The following is unnecessary, because UnicastRemoteObject export itself automatically. + //((UnicastServerRef)getRef()).exportObject(this); +} + +public Remote lookup(String name) throws RemoteException, NotBoundException, AccessException { + Object obj = bindings.get(name); + if (obj == null) { + throw new NotBoundException(name); + } + return ((Remote)obj); +} + +public void bind(String name, Remote obj) throws RemoteException, AlreadyBoundException, AccessException { + if (bindings.containsKey(name)) { + throw new AlreadyBoundException(name); + } + bindings.put(name, obj); +} + +public void unbind(String name) throws RemoteException, NotBoundException, AccessException { + Object obj = bindings.remove(name); + if (obj == null) { + throw new NotBoundException(name); + } +} + +public void rebind(String name, Remote obj) throws RemoteException, AccessException { + bindings.put(name, obj); +} + +public String[] list() throws RemoteException, AccessException { + int size = bindings.size(); + String[] strings = new String[size]; + Enumeration e = bindings.keys(); + for (int i = 0; i < size; i++) { + strings[i] = (String)e.nextElement(); + } + return (strings); +} + +public static void version() { + System.out.println("rmiregistry (" + + System.getProperty("java.vm.name") + + ") " + + System.getProperty("java.vm.version")); + System.out.println("Copyright 2011 Free Software Foundation, Inc."); + System.out.println("This is free software; see the source for copying conditions. There is NO"); + System.out.println("warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."); + System.exit(0); +} + +public static void help() { + System.out.println( +"Usage: rmiregistry [OPTION | PORT]\n" + +"\n" + +" --help Print this help, then exit\n" + +" --version Print version number, then exit\n"); + System.exit(0); +} + +public static void main(String[] args) { + int port = Registry.REGISTRY_PORT; + if (args.length > 0) { + if (args[0].equals("--version")) { + version(); + } + else if (args[0].equals("--help")) { + help(); + } + try { + port = Integer.parseInt(args[0]); + } + catch (NumberFormatException _) { + System.err.println("Bad port number - using default"); + } + } + + try { + Registry impl = LocateRegistry.createRegistry(port); + } + catch (RemoteException _) { + System.err.println("Registry failed"); + } +} + +} diff --git a/libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Skel.java b/libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Skel.java new file mode 100644 index 000000000..defa3bf61 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Skel.java @@ -0,0 +1,227 @@ +/* RegistryImpl_Skel.java + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +// Skel class generated by rmic - DO NOT EDIT! + +package gnu.java.rmi.registry; + +public final class RegistryImpl_Skel + implements java.rmi.server.Skeleton +{ + private static final long interfaceHash = 4905912898345647071L; + + private static final java.rmi.server.Operation[] operations = { + new java.rmi.server.Operation("void bind(java.lang.String, java.rmi.Remote"), + new java.rmi.server.Operation("java.lang.String[] list("), + new java.rmi.server.Operation("java.rmi.Remote lookup(java.lang.String"), + new java.rmi.server.Operation("void rebind(java.lang.String, java.rmi.Remote"), + new java.rmi.server.Operation("void unbind(java.lang.String") + }; + + public java.rmi.server.Operation[] getOperations() { + return ((java.rmi.server.Operation[]) operations.clone()); + } + + public void dispatch(java.rmi.Remote obj, java.rmi.server.RemoteCall call, int opnum, long hash) throws java.lang.Exception { + if (opnum < 0) { + if (hash == 7583982177005850366L) { + opnum = 0; + } + else if (hash == 2571371476350237748L) { + opnum = 1; + } + else if (hash == -7538657168040752697L) { + opnum = 2; + } + else if (hash == -8381844669958460146L) { + opnum = 3; + } + else if (hash == 7305022919901907578L) { + opnum = 4; + } + else { + throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch"); + } + } + else if (hash != interfaceHash) { + throw new java.rmi.server.SkeletonMismatchException("interface hash mismatch"); + } + + gnu.java.rmi.registry.RegistryImpl server = (gnu.java.rmi.registry.RegistryImpl)obj; + switch (opnum) { + case 0: + { + java.lang.String $param_0; + java.rmi.Remote $param_1; + try { + java.io.ObjectInput in = call.getInputStream(); + $param_0 = (java.lang.String)in.readObject(); + $param_1 = (java.rmi.Remote)in.readObject(); + + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + catch (java.lang.ClassCastException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + finally { + call.releaseInputStream(); + } + server.bind($param_0, $param_1); + try { + java.io.ObjectOutput out = call.getResultStream(true); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling return", e); + } + break; + } + + case 1: + { + try { + java.io.ObjectInput in = call.getInputStream(); + + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + finally { + call.releaseInputStream(); + } + java.lang.String[] $result = server.list(); + try { + java.io.ObjectOutput out = call.getResultStream(true); + out.writeObject($result); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling return", e); + } + break; + } + + case 2: + { + java.lang.String $param_0; + try { + java.io.ObjectInput in = call.getInputStream(); + $param_0 = (java.lang.String)in.readObject(); + + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + catch (java.lang.ClassCastException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + finally { + call.releaseInputStream(); + } + java.rmi.Remote $result = server.lookup($param_0); + try { + java.io.ObjectOutput out = call.getResultStream(true); + out.writeObject($result); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling return", e); + } + break; + } + + case 3: + { + java.lang.String $param_0; + java.rmi.Remote $param_1; + try { + java.io.ObjectInput in = call.getInputStream(); + $param_0 = (java.lang.String)in.readObject(); + $param_1 = (java.rmi.Remote)in.readObject(); + + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + catch (java.lang.ClassCastException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + finally { + call.releaseInputStream(); + } + server.rebind($param_0, $param_1); + try { + java.io.ObjectOutput out = call.getResultStream(true); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling return", e); + } + break; + } + + case 4: + { + java.lang.String $param_0; + try { + java.io.ObjectInput in = call.getInputStream(); + $param_0 = (java.lang.String)in.readObject(); + + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + catch (java.lang.ClassCastException e) { + throw new java.rmi.UnmarshalException("error unmarshalling arguments", e); + } + finally { + call.releaseInputStream(); + } + server.unbind($param_0); + try { + java.io.ObjectOutput out = call.getResultStream(true); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling return", e); + } + break; + } + + default: + throw new java.rmi.UnmarshalException("invalid method number"); + } + } +} diff --git a/libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Stub.java b/libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Stub.java new file mode 100644 index 000000000..786a5e180 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/registry/RegistryImpl_Stub.java @@ -0,0 +1,293 @@ +/* RegistryImpl_Stub.java + Copyright (C) 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +// Stub class generated by rmic - DO NOT EDIT! + +package gnu.java.rmi.registry; + +public final class RegistryImpl_Stub + extends java.rmi.server.RemoteStub + implements java.rmi.registry.Registry +{ + private static final long serialVersionUID = 2L; + + private static final long interfaceHash = 4905912898345647071L; + + private static boolean useNewInvoke; + + private static final java.rmi.server.Operation[] operations = { + new java.rmi.server.Operation("void bind(java.lang.String, java.rmi.Remote)"), + new java.rmi.server.Operation("java.lang.String[] list()"), + new java.rmi.server.Operation("java.rmi.Remote lookup(java.lang.String)"), + new java.rmi.server.Operation("void rebind(java.lang.String, java.rmi.Remote)"), + new java.rmi.server.Operation("void unbind(java.lang.String)") + }; + + private static java.lang.reflect.Method $method_bind_0; + private static java.lang.reflect.Method $method_list_1; + private static java.lang.reflect.Method $method_lookup_2; + private static java.lang.reflect.Method $method_rebind_3; + private static java.lang.reflect.Method $method_unbind_4; + + static { + try { + java.rmi.server.RemoteRef.class.getMethod("invoke", new java.lang.Class[] { java.rmi.Remote.class, java.lang.reflect.Method.class, java.lang.Object[].class, long.class }); + useNewInvoke = false; + $method_bind_0 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("bind", new java.lang.Class[] {java.lang.String.class, java.rmi.Remote.class}); + $method_list_1 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("list", new java.lang.Class[] {}); + $method_lookup_2 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("lookup", new java.lang.Class[] {java.lang.String.class}); + $method_rebind_3 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("rebind", new java.lang.Class[] {java.lang.String.class, java.rmi.Remote.class}); + $method_unbind_4 = gnu.java.rmi.registry.RegistryImpl.class.getMethod("unbind", new java.lang.Class[] {java.lang.String.class}); + + } + catch (java.lang.NoSuchMethodException e) { + useNewInvoke = false; + } + } + + public RegistryImpl_Stub() { + super(); + } + public RegistryImpl_Stub(java.rmi.server.RemoteRef ref) { + super(ref); + } + + public void bind(java.lang.String $param_0, java.rmi.Remote $param_1) throws java.rmi.AccessException, java.rmi.AlreadyBoundException, java.rmi.RemoteException { + try { + if (useNewInvoke) { + ref.invoke(this, $method_bind_0, new java.lang.Object[] {$param_0, $param_1}, 7583982177005850366L); + } + else { + java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, 0, interfaceHash); + try { + java.io.ObjectOutput out = call.getOutputStream(); + out.writeObject($param_0); + out.writeObject($param_1); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling arguments", e); + } + ref.invoke(call); + try { + java.io.ObjectInput in = call.getInputStream(); + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling return", e); + } + finally { + ref.done(call); + } + } + } + catch (java.rmi.AccessException e) { + throw e; + } + catch (java.rmi.AlreadyBoundException e) { + throw e; + } + catch (java.rmi.RemoteException e) { + throw e; + } + catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } + + public java.lang.String[] list() throws java.rmi.AccessException, java.rmi.RemoteException { + try { + if (useNewInvoke) { + java.lang.Object $result = ref.invoke(this, $method_list_1, null, 2571371476350237748L); + return ((java.lang.String[])$result); + } + else { + java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, 1, interfaceHash); + try { + java.io.ObjectOutput out = call.getOutputStream(); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling arguments", e); + } + ref.invoke(call); + java.lang.String[] $result; + try { + java.io.ObjectInput in = call.getInputStream(); + $result = (java.lang.String[])in.readObject(); + return ($result); + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling return", e); + } + finally { + ref.done(call); + } + } + } + catch (java.rmi.AccessException e) { + throw e; + } + catch (java.rmi.RemoteException e) { + throw e; + } + catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } + + public java.rmi.Remote lookup(java.lang.String $param_0) throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException { + try { + if (useNewInvoke) { + java.lang.Object $result = ref.invoke(this, $method_lookup_2, new java.lang.Object[] {$param_0}, -7538657168040752697L); + return ((java.rmi.Remote)$result); + } + else { + java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, 2, interfaceHash); + try { + java.io.ObjectOutput out = call.getOutputStream(); + out.writeObject($param_0); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling arguments", e); + } + ref.invoke(call); + java.rmi.Remote $result; + try { + java.io.ObjectInput in = call.getInputStream(); + $result = (java.rmi.Remote)in.readObject(); + return ($result); + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling return", e); + } + finally { + ref.done(call); + } + } + } + catch (java.rmi.AccessException e) { + throw e; + } + catch (java.rmi.NotBoundException e) { + throw e; + } + catch (java.rmi.RemoteException e) { + throw e; + } + catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } + + public void rebind(java.lang.String $param_0, java.rmi.Remote $param_1) throws java.rmi.AccessException, java.rmi.RemoteException { + try { + if (useNewInvoke) { + ref.invoke(this, $method_rebind_3, new java.lang.Object[] {$param_0, $param_1}, -8381844669958460146L); + } + else { + java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, 3, interfaceHash); + try { + java.io.ObjectOutput out = call.getOutputStream(); + out.writeObject($param_0); + out.writeObject($param_1); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling arguments", e); + } + ref.invoke(call); + try { + java.io.ObjectInput in = call.getInputStream(); + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling return", e); + } + finally { + ref.done(call); + } + } + } + catch (java.rmi.AccessException e) { + throw e; + } + catch (java.rmi.RemoteException e) { + throw e; + } + catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } + + public void unbind(java.lang.String $param_0) throws java.rmi.AccessException, java.rmi.NotBoundException, java.rmi.RemoteException { + try { + if (useNewInvoke) { + ref.invoke(this, $method_unbind_4, new java.lang.Object[] {$param_0}, 7305022919901907578L); + } + else { + java.rmi.server.RemoteCall call = ref.newCall((java.rmi.server.RemoteObject)this, operations, 4, interfaceHash); + try { + java.io.ObjectOutput out = call.getOutputStream(); + out.writeObject($param_0); + } + catch (java.io.IOException e) { + throw new java.rmi.MarshalException("error marshalling arguments", e); + } + ref.invoke(call); + try { + java.io.ObjectInput in = call.getInputStream(); + } + catch (java.io.IOException e) { + throw new java.rmi.UnmarshalException("error unmarshalling return", e); + } + finally { + ref.done(call); + } + } + } + catch (java.rmi.AccessException e) { + throw e; + } + catch (java.rmi.NotBoundException e) { + throw e; + } + catch (java.rmi.RemoteException e) { + throw e; + } + catch (java.lang.Exception e) { + throw new java.rmi.UnexpectedException("undeclared checked exception", e); + } + } + +} diff --git a/libjava/classpath/gnu/java/rmi/registry/package.html b/libjava/classpath/gnu/java/rmi/registry/package.html new file mode 100644 index 000000000..3750359d6 --- /dev/null +++ b/libjava/classpath/gnu/java/rmi/registry/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.rmi.registry + + +

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

+ + + diff --git a/libjava/classpath/gnu/java/security/.cvsignore b/libjava/classpath/gnu/java/security/.cvsignore new file mode 100644 index 000000000..11f6639eb --- /dev/null +++ b/libjava/classpath/gnu/java/security/.cvsignore @@ -0,0 +1 @@ +Configuration.java diff --git a/libjava/classpath/gnu/java/security/Configuration.java.in b/libjava/classpath/gnu/java/security/Configuration.java.in new file mode 100644 index 000000000..1deb543d4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/Configuration.java.in @@ -0,0 +1,56 @@ +/* Configuration.java -- + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.security; + +/** + * This file defines compile-time constants that can be accessed by + * our crypto code. All crypto code should use and define such + * constants here instead of using the gnu.classpath.Configuration class. + */ +public interface Configuration +{ + + /** + * The value of DEBUG is substituted according to whether the + * "--enable-debug" argument was passed to configure. Code + * which is made conditional based on the value of this flag - typically + * code that generates debugging output - will be removed by the optimizer + * in a non-debug build. + */ + boolean DEBUG = @LIBDEBUG@; +} diff --git a/libjava/classpath/gnu/java/security/Engine.java b/libjava/classpath/gnu/java/security/Engine.java new file mode 100644 index 000000000..969fcef6c --- /dev/null +++ b/libjava/classpath/gnu/java/security/Engine.java @@ -0,0 +1,282 @@ +/* Engine -- generic getInstance method. + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.security; + +import gnu.java.lang.CPStringBuilder; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.util.Enumeration; + +/** + * Generic implementation of the getInstance methods in the various + * engine classes in java.security. + *

+ * These classes ({@link java.security.Signature} for example) can be + * thought of as the "chrome, upholstery, and steering wheel", and the SPI + * (service provider interface, e.g. {@link java.security.SignatureSpi}) + * classes can be thought of as the "engine" -- providing the actual + * functionality of whatever cryptographic algorithm the instance + * represents. + * + * @see Provider + * @author Casey Marshall + */ +public final class Engine +{ + + // Constants. + // ------------------------------------------------------------------------ + + /** Prefix for aliases. */ + private static final String ALG_ALIAS = "Alg.Alias."; + + /** Maximum number of aliases to try. */ + private static final int MAX_ALIASES = 5; + + /** Argument list for no-argument constructors. */ + private static final Object[] NO_ARGS = new Object[0]; + + // Constructor. + // ------------------------------------------------------------------------ + + /** This class cannot be instantiated. */ + private Engine() { } + + /** + * Return the implementation for algorithm for service service + * from provider. The service is e.g. "Signature", and the algorithm + * "DSA". + * + * @param service The service name. + * @param algorithm The name of the algorithm to get. + * @param provider The provider to get the implementation from. + * @return The engine class for the specified algorithm; the object returned + * is typically a subclass of the SPI class for that service, but + * callers should check that this is so. + * @throws NoSuchAlgorithmException If the implementation cannot be found or + * cannot be instantiated. + * @throws InvocationTargetException If the SPI class's constructor throws an + * exception. + * @throws IllegalArgumentException If any of the three arguments is null. + */ + public static Object getInstance(String service, String algorithm, + Provider provider) + throws InvocationTargetException, NoSuchAlgorithmException + { + return getInstance(service, algorithm, provider, NO_ARGS); + } + + /** + * Return the implementation for algorithm for service service + * from provider, passing initArgs to the SPI class's + * constructor (which cannot be null; pass a zero-length array if the SPI + * takes no arguments). The service is e.g. "Signature", and the algorithm + * "DSA". + * + * @param service The service name. + * @param algorithm The name of the algorithm to get. + * @param provider The provider to get the implementation from. + * @param initArgs The arguments to pass to the SPI class's constructor + * (cannot be null). + * @return The engine class for the specified algorithm; the object returned + * is typically a subclass of the SPI class for that service, but + * callers should check that this is so. + * @throws NoSuchAlgorithmException If the implementation cannot be found or + * cannot be instantiated. + * @throws InvocationTargetException If the SPI class's constructor throws an + * exception. + * @throws IllegalArgumentException If any of the four arguments is + * null or if either service, or + * algorithm is an empty string. + */ + public static Object getInstance(String service, String algorithm, + Provider provider, Object[] initArgs) + throws InvocationTargetException, NoSuchAlgorithmException + { + if (service == null) + throw new IllegalArgumentException("service MUST NOT be null"); + service = service.trim(); + if (service.length() == 0) + throw new IllegalArgumentException("service MUST NOT be empty"); + if (algorithm == null) + throw new IllegalArgumentException("algorithm MUST NOT be null"); + algorithm = algorithm.trim(); + if (algorithm.length() == 0) + throw new IllegalArgumentException("algorithm MUST NOT be empty"); + if (provider == null) + throw new IllegalArgumentException("provider MUST NOT be null"); + if (initArgs == null) + throw new IllegalArgumentException("Constructor's parameters MUST NOT be null"); + + Enumeration enumer = provider.propertyNames(); + String key = null; + String alias; + int count = 0; + boolean algorithmFound = false; + CPStringBuilder sb = new CPStringBuilder(); + while (enumer.hasMoreElements()) + { + key = (String) enumer.nextElement(); + if (key.equalsIgnoreCase(service + "." + algorithm)) + { + // remove the service portion from the key + algorithm = key.substring(service.length() + 1); + algorithmFound = true; + break; + } + else if (key.equalsIgnoreCase(ALG_ALIAS + service + "." + algorithm)) + { + alias = provider.getProperty(key); + if (! algorithm.equalsIgnoreCase(alias)) // does not refer to itself + { + algorithm = alias; + if (count++ > MAX_ALIASES) + { + sb.append("Algorithm [").append(algorithm) + .append("] of type [").append(service) + .append("] from provider [").append(provider) + .append("] has too many aliases"); + throw new NoSuchAlgorithmException(sb.toString()); + } + // need to reset enumeration to now look for the alias + enumer = provider.propertyNames(); + } + } + } + + if (! algorithmFound) + { + sb.append("Algorithm [").append(algorithm).append("] of type [") + .append(service).append("] from provider [") + .append(provider).append("] is not found"); + throw new NoSuchAlgorithmException(sb.toString()); + } + + // Find and instantiate the implementation + Class clazz = null; + ClassLoader loader = provider.getClass().getClassLoader(); + Constructor constructor = null; + String className = provider.getProperty(key); + sb.append("Class [").append(className).append("] for algorithm [") + .append(algorithm).append("] of type [").append(service) + .append("] from provider [").append(provider).append("] "); + Throwable cause = null; + try + { + if (loader != null) + clazz = loader.loadClass(className); + else + clazz = Class.forName(className); + constructor = getCompatibleConstructor(clazz, initArgs); + return constructor.newInstance(initArgs); + } + catch (ClassNotFoundException x) + { + sb.append("cannot not be found"); + cause = x; + } + catch (IllegalAccessException x) + { + sb.append("cannot be accessed"); + cause = x; + } + catch (InstantiationException x) + { + sb.append("cannot be instantiated"); + cause = x; + } + catch (ExceptionInInitializerError x) + { + sb.append("cannot be initialized"); + cause = x; + } + catch (SecurityException x) + { + sb.append("caused a security violation"); + cause = x; + } + catch (NoSuchMethodException x) + { + sb.append("does not have/expose an appropriate constructor"); + cause = x; + } + + NoSuchAlgorithmException x = new NoSuchAlgorithmException(sb.toString()); + x.initCause(cause); + throw x; + } + + /** + * Find a constructor in the given class that can take the specified + * argument list, allowing any of which to be null. + * + * @param clazz The class from which to get the constructor. + * @param initArgs The argument list to be passed to the constructor. + * @return The constructor. + * @throws NoSuchMethodException If no constructor of the given class + * can take the specified argument array. + */ + private static Constructor getCompatibleConstructor(Class clazz, + Object[] initArgs) + throws NoSuchMethodException + { + Constructor[] c = clazz.getConstructors(); + outer:for (int i = 0; i < c.length; i++) + { + Class[] argTypes = c[i].getParameterTypes(); + if (argTypes.length != initArgs.length) + continue; + for (int j = 0; j < argTypes.length; j++) + { + if (initArgs[j] != null && + !argTypes[j].isAssignableFrom(initArgs[j].getClass())) + continue outer; + } + // If we reach this point, we know this constructor (c[i]) has + // the same number of parameters as the target parameter list, + // and all our parameters are either (1) null, or (2) assignable + // to the target parameter type. + return c[i]; + } + throw new NoSuchMethodException(); + } +} diff --git a/libjava/classpath/gnu/java/security/OID.java b/libjava/classpath/gnu/java/security/OID.java new file mode 100644 index 000000000..c7efe6557 --- /dev/null +++ b/libjava/classpath/gnu/java/security/OID.java @@ -0,0 +1,512 @@ +/* OID.java -- numeric representation of an object identifier + Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.der.DEREncodingException; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.StringTokenizer; + +/** + * This immutable class represents an object identifier, or OID. + * + *

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

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

OIDs may be relative, in which case the first two elements of the + * OID are omitted. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class OID implements Cloneable, Comparable, java.io.Serializable +{ + + // Fields. + // ------------------------------------------------------------------------ + + /* Serial version id for serialization. */ + static final long serialVersionUID = 5722492029044597779L; + + /** + * The numeric ID structure. + */ + private int[] components; + + /** + * The string representation of this OID, in dotted-decimal format. + */ + private transient String strRep; + + /** + * The DER encoding of this OID. + */ + private transient byte[] der; + + /** + * Whether or not this OID is relative. + */ + private boolean relative; + + // Constructors. + // ------------------------------------------------------------------------ + + /** + * Create a new OID from the given byte array. The argument (which can + * neither be null nor zero-length) is copied to prevent subsequent + * modification. + * + * @param components The numeric IDs. + * @throws IllegalArgumentException If components is null or empty. + */ + public OID(int[] components) + { + this(components, false); + } + + /** + * Create a new OID from the given byte array. The argument (which can + * neither be null nor zero-length) is copied to prevent subsequent + * modification. + * + * @param components The numeric IDs. + * @param relative The relative flag. + * @throws IllegalArgumentException If components is null or empty. + */ + public OID(int[] components, boolean relative) + { + if (components == null || components.length == 0) + throw new IllegalArgumentException(); + this.components = (int[]) components.clone(); + this.relative = relative; + } + + /** + * Create a new OID from the given dotted-decimal representation. + * + * @param strRep The string representation of the OID. + * @throws IllegalArgumentException If the string does not contain at + * least one integer. + * @throws NumberFormatException If the string does not contain only + * numbers and periods ('.'). + */ + public OID(String strRep) + { + this(strRep, false); + } + + /** + * Create a new OID from the given dotted-decimal representation. + * + * @param strRep The string representation of the OID. + * @param relative The relative flag. + * @throws IllegalArgumentException If the string does not contain at + * least one integer. + * @throws NumberFormatException If the string does not contain only + * numbers and periods ('.'). + */ + public OID(String strRep, boolean relative) + { + this.relative = relative; + this.strRep = strRep; + components = fromString(strRep); + } + + /** + * Construct a new OID from the DER bytes in an input stream. This method + * does not read the tag or the length field from the input stream, so + * the caller must supply the number of octets in this OID's encoded + * form. + * + * @param derIn The DER input stream. + * @param len The number of bytes in the encoded form. + * @throws IOException If an error occurs reading the OID. + */ + public OID(InputStream derIn, int len) throws IOException + { + this(derIn, len, false); + } + + /** + * Construct a new OID from the DER bytes in an input stream. This method + * does not read the tag or the length field from the input stream, so + * the caller must supply the number of octets in this OID's encoded + * form. + * + * @param derIn The DER input stream. + * @param len The number of bytes in the encoded form. + * @param relative The relative flag. + * @throws IOException If an error occurs reading the OID. + */ + public OID(InputStream derIn, int len, boolean relative) throws IOException + { + der = new byte[len]; + derIn.read(der); + this.relative = relative; + try + { + components = fromDER(der, relative); + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + aioobe.printStackTrace(); + throw aioobe; + } + } + + /** + * Construct a new OID from the given DER bytes. + * + * @param encoded The DER encoded OID. + * @throws IOException If an error occurs reading the OID. + */ + public OID(byte[] encoded) throws IOException + { + this(encoded, false); + } + + /** + * Construct a new OID from the given DER bytes. + * + * @param encoded The encoded relative OID. + * @param relative The relative flag. + */ + public OID(byte[] encoded, boolean relative) throws IOException + { + der = (byte[]) encoded.clone(); + this.relative = relative; + try + { + components = fromDER(der, relative); + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + aioobe.printStackTrace(); + throw aioobe; + } + } + + // Instance methods. + // ------------------------------------------------------------------------ + + /** + * Return the numeric IDs of this OID. The value returned is copied to + * prevent modification. + * + * @return The IDs in a new integer array. + */ + public int[] getIDs() + { + return (int[]) components.clone(); + } + + /** + * Get the DER encoding of this OID, minus the tag and length fields. + * + * @return The DER bytes. + */ + public byte[] getDER() + { + if (der == null) + { + ByteArrayOutputStream bout = new ByteArrayOutputStream(); + int i = 0; + if (!relative) + { + int b = components[i++] * 40 + (components.length > 1 + ? components[i++] : 0); + encodeSubID(bout, b); + } + for ( ; i < components.length; i++) + encodeSubID(bout, components[i]); + der = bout.toByteArray(); + } + return (byte[]) der.clone(); + } + + /** + * Get the parent OID of this OID. That is, if this OID is "1.2.3.4", + * then the parent OID will be "1.2.3". If this OID is a top-level + * OID, this method returns null. + * + * @return The parent OID, or null. + */ + public OID getParent() + { + if (components.length == 1) + return null; + int[] parent = new int[components.length - 1]; + System.arraycopy(components, 0, parent, 0, parent.length); + return new OID(parent); + } + + public OID getChild(int id) + { + int[] child = new int[components.length + 1]; + System.arraycopy(components, 0, child, 0, components.length); + child[child.length - 1] = id; + return new OID(child); + } + + /** + * Get the root OID of this OID. That is, the first two components. + * + * @return The root OID. + */ + public OID getRoot() + { + if (components.length <= 2) + return this; + int[] root = new int[2]; + root[0] = components[0]; + root[1] = components[1]; + return new OID(root); + } + + public boolean isRelative() + { + return relative; + } + + /** + * Returns a copy of this OID. + * + * @return The copy. + */ + public Object clone() + { + try + { + return super.clone(); + } + catch (CloneNotSupportedException cnse) + { + InternalError ie = new InternalError(); + ie.initCause(cnse); + throw ie; + } + } + + /* Nice idea, but possibly too expensive for whatever benefit it + * provides. + + public String getShortName() + { + return OIDTable.getShortName(this); + } + + public String getLongName() + { + return OIDTable.getLongName(this); + } + + */ + + /** + * Returns the value of this OID in dotted-decimal format. + * + * @return The string representation. + */ + public String toString() + { + if (strRep != null) + return strRep; + else + { + CPStringBuilder buf = new CPStringBuilder(); + for (int i = 0; i < components.length; i++) + { + buf.append((long) components[i] & 0xFFFFFFFFL); + if (i < components.length - 1) + buf.append('.'); + } + return (strRep = buf.toString()); + } + } + + /** + * Computes a hash code for this OID. + * + * @return The hash code. + */ + public int hashCode() + { + int ret = 0; + for (int i = 0; i < components.length; i++) + ret += components[i] << (i & 31); + return ret; + } + + /** + * Tests whether or not this OID equals another. + * + * @return Whether or not this OID equals the other. + */ + public boolean equals(Object o) + { + if (!(o instanceof OID)) + return false; + return java.util.Arrays.equals(components, ((OID) o).components); + } + + /** + * Compares this OID to another. The comparison is essentially + * lexicographic, where the two OIDs are compared until their + * first difference, then that difference is returned. If one OID is + * shorter, but all elements equal between the two for the shorter + * length, then the shorter OID is lesser than the longer. + * + * @param o The object to compare. + * @return An integer less than, equal to, or greater than zero if + * this object is less than, equal to, or greater than the + * argument. + * @throws ClassCastException If o is not an OID. + */ + public int compareTo(Object o) + { + if (equals(o)) + return 0; + int[] components2 = ((OID) o).components; + int len = Math.min(components.length, components2.length); + for (int i = 0; i < len; i++) + { + if (components[i] != components2[i]) + return (components[i] < components2[i]) ? -1 : 1; + } + if (components.length == components2.length) + return 0; + return (components.length < components2.length) ? -1 : 1; + } + + // Own methods. + // ------------------------------------------------------------------------ + + private static int[] fromDER(byte[] der, boolean relative) + throws DEREncodingException + { + // cannot be longer than this. + int[] components = new int[der.length + 1]; + int count = 0; + int i = 0; + if (!relative && i < der.length) + { + // Non-relative OIDs have the first two arcs coded as: + // + // i = first_arc * 40 + second_arc; + // + int j = (der[i] & 0xFF); + components[count++] = j / 40; + components[count++] = j % 40; + i++; + } + while (i < der.length) + { + int j = 0; + do + { + j = der[i++] & 0xFF; + components[count] <<= 7; + components[count] |= j & 0x7F; + if (i >= der.length && (j & 0x80) != 0) + throw new DEREncodingException("malformed OID"); + } + while ((j & 0x80) != 0); + count++; + } + if (count == components.length) + return components; + int[] ret = new int[count]; + System.arraycopy(components, 0, ret, 0, count); + return ret; + } + + private static int[] fromString(String strRep) throws NumberFormatException + { + if (strRep.startsWith("OID.") || strRep.startsWith("oid.")) + strRep = strRep.substring(4); + StringTokenizer tok = new StringTokenizer(strRep, "."); + if (tok.countTokens() == 0) + throw new IllegalArgumentException(); + int[] components = new int[tok.countTokens()]; + int i = 0; + while (tok.hasMoreTokens()) + { + components[i++] = Integer.parseInt(tok.nextToken()); + } + return components; + } + + private static void encodeSubID(ByteArrayOutputStream out, int id) + { + if (id < 128) + { + out.write(id); + } + else if (id < 16384) + { + out.write((id >>> 7) | 0x80); + out.write(id & 0x7F); + } + else if (id < 2097152) + { + out.write((id >>> 14) | 0x80); + out.write(((id >>> 7) | 0x80) & 0xFF); + out.write(id & 0x7F); + } + else if (id < 268435456) + { + out.write( (id >>> 21) | 0x80); + out.write(((id >>> 14) | 0x80) & 0xFF); + out.write(((id >>> 7) | 0x80) & 0xFF); + out.write(id & 0x7F); + } + } +} diff --git a/libjava/classpath/gnu/java/security/PolicyFile.java b/libjava/classpath/gnu/java/security/PolicyFile.java new file mode 100644 index 000000000..0560bce07 --- /dev/null +++ b/libjava/classpath/gnu/java/security/PolicyFile.java @@ -0,0 +1,687 @@ +/* PolicyFile.java -- policy file reader + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.security; + +import gnu.classpath.debug.Component; +import gnu.classpath.debug.SystemLogger; + +import gnu.java.lang.CPStringBuilder; +import gnu.java.security.action.GetPropertyAction; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.StreamTokenizer; +import java.lang.reflect.Constructor; +import java.net.MalformedURLException; +import java.net.URL; +import java.security.AccessController; +import java.security.CodeSource; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.security.Policy; +import java.security.Principal; +import java.security.PrivilegedActionException; +import java.security.PrivilegedExceptionAction; +import java.security.Security; +import java.security.UnresolvedPermission; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.StringTokenizer; +import java.util.logging.Logger; + +/** + * An implementation of a {@link java.security.Policy} object whose + * permissions are specified by a policy file. + * + *

The approximate syntax of policy files is:

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

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

+ * + *

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

+ * + *
    + *
  1. The file ${java.home}/lib/security/java.policy.
  2. + *
  3. All URLs specified by security properties + * "policy.file.n", for increasing n + * starting from 1. The sequence stops at the first undefined + * property, so you must set "policy.file.1" if you also + * set "policy.file.2", and so on.
  4. + *
  5. The URL specified by the property + * "java.security.policy".
  6. + *
+ * + * @author Casey Marshall (csm@gnu.org) + * @see java.security.Policy + */ +public final class PolicyFile extends Policy +{ + + // Constants and fields. + // ------------------------------------------------------------------------- + + protected static final Logger logger = SystemLogger.SYSTEM; + // Added to cut redundant AccessController.doPrivileged calls + private static GetPropertyAction prop = new GetPropertyAction("file.separator"); + private static final String fs = (String) AccessController.doPrivileged(prop); + + private static final String DEFAULT_POLICY = + (String) AccessController.doPrivileged(prop.setParameters("java.home")) + + fs + "lib" + fs + "security" + fs + "java.policy"; + private static final String DEFAULT_USER_POLICY = + (String) AccessController.doPrivileged(prop.setParameters("user.home")) + + fs + ".java.policy"; + + private final Map cs2pc; + + // Constructors. + // ------------------------------------------------------------------------- + + public PolicyFile() + { + cs2pc = new HashMap(); + refresh(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public PermissionCollection getPermissions(CodeSource codeSource) + { + Permissions perms = new Permissions(); + for (Iterator it = cs2pc.entrySet().iterator(); it.hasNext(); ) + { + Map.Entry e = (Map.Entry) it.next(); + CodeSource cs = (CodeSource) e.getKey(); + if (cs.implies(codeSource)) + { + logger.log (Component.POLICY, "{0} -> {1}", new Object[] + { cs, codeSource }); + PermissionCollection pc = (PermissionCollection) e.getValue(); + for (Enumeration ee = pc.elements(); ee.hasMoreElements(); ) + { + perms.add((Permission) ee.nextElement()); + } + } + else + logger.log (Component.POLICY, "{0} !-> {1}", new Object[] + { cs, codeSource }); + } + logger.log (Component.POLICY, "returning permissions {0} for {1}", + new Object[] { perms, codeSource }); + return perms; + } + + public void refresh() + { + cs2pc.clear(); + final List policyFiles = new LinkedList(); + try + { + policyFiles.add (new File (DEFAULT_POLICY).toURL()); + policyFiles.add (new File (DEFAULT_USER_POLICY).toURL ()); + + AccessController.doPrivileged( + new PrivilegedExceptionAction() + { + public Object run() throws Exception + { + String allow = Security.getProperty ("policy.allowSystemProperty"); + if (allow == null || Boolean.getBoolean (allow)) + { + String s = System.getProperty ("java.security.policy"); + logger.log (Component.POLICY, "java.security.policy={0}", s); + if (s != null) + { + boolean only = s.startsWith ("="); + if (only) + s = s.substring (1); + policyFiles.clear (); + policyFiles.add (new URL (s)); + if (only) + return null; + } + } + for (int i = 1; ; i++) + { + String pname = "policy.url." + i; + String s = Security.getProperty (pname); + logger.log (Component.POLICY, "{0}={1}", new Object [] + { pname, s }); + if (s == null) + break; + policyFiles.add (new URL (s)); + } + return null; + } + }); + } + catch (PrivilegedActionException pae) + { + logger.log (Component.POLICY, "reading policy properties", pae); + } + catch (MalformedURLException mue) + { + logger.log (Component.POLICY, "setting default policies", mue); + } + + logger.log (Component.POLICY, "building policy from URLs {0}", + policyFiles); + for (Iterator it = policyFiles.iterator(); it.hasNext(); ) + { + try + { + URL url = (URL) it.next(); + parse(url); + } + catch (IOException ioe) + { + logger.log (Component.POLICY, "reading policy", ioe); + } + } + } + + public String toString() + { + return super.toString() + " [ " + cs2pc.toString() + " ]"; + } + + // Own methods. + // ------------------------------------------------------------------------- + + private static final int STATE_BEGIN = 0; + private static final int STATE_GRANT = 1; + private static final int STATE_PERMS = 2; + + /** + * Parse a policy file, incorporating the permission definitions + * described therein. + * + * @param url The URL of the policy file to read. + * @throws IOException if an I/O error occurs, or if the policy file + * cannot be parsed. + */ + private void parse(final URL url) throws IOException + { + logger.log (Component.POLICY, "reading policy file from {0}", url); + final StreamTokenizer in = new StreamTokenizer(new InputStreamReader(url.openStream())); + in.resetSyntax(); + in.slashSlashComments(true); + in.slashStarComments(true); + in.wordChars('A', 'Z'); + in.wordChars('a', 'z'); + in.wordChars('0', '9'); + in.wordChars('.', '.'); + in.wordChars('_', '_'); + in.wordChars('$', '$'); + in.whitespaceChars(' ', ' '); + in.whitespaceChars('\t', '\t'); + in.whitespaceChars('\f', '\f'); + in.whitespaceChars('\n', '\n'); + in.whitespaceChars('\r', '\r'); + in.quoteChar('\''); + in.quoteChar('"'); + + int tok; + int state = STATE_BEGIN; + List keystores = new LinkedList(); + URL currentBase = null; + List currentCerts = new LinkedList(); + Permissions currentPerms = new Permissions(); + while ((tok = in.nextToken()) != StreamTokenizer.TT_EOF) + { + switch (tok) + { + case '{': + if (state != STATE_GRANT) + error(url, in, "spurious '{'"); + state = STATE_PERMS; + tok = in.nextToken(); + break; + case '}': + if (state != STATE_PERMS) + error(url, in, "spurious '}'"); + state = STATE_BEGIN; + currentPerms.setReadOnly(); + Certificate[] c = null; + if (!currentCerts.isEmpty()) + c = (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()]); + cs2pc.put(new CodeSource(currentBase, c), currentPerms); + currentCerts.clear(); + currentPerms = new Permissions(); + currentBase = null; + tok = in.nextToken(); + if (tok != ';') + in.pushBack(); + continue; + } + if (tok != StreamTokenizer.TT_WORD) + { + error(url, in, "expecting word token"); + } + + // keystore "" [',' ""] ';' + if (in.sval.equalsIgnoreCase("keystore")) + { + String alg = KeyStore.getDefaultType(); + tok = in.nextToken(); + if (tok != '"' && tok != '\'') + error(url, in, "expecting key store URL"); + String store = in.sval; + tok = in.nextToken(); + if (tok == ',') + { + tok = in.nextToken(); + if (tok != '"' && tok != '\'') + error(url, in, "expecting key store type"); + alg = in.sval; + tok = in.nextToken(); + } + if (tok != ';') + error(url, in, "expecting semicolon"); + try + { + KeyStore keystore = KeyStore.getInstance(alg); + keystore.load(new URL(url, store).openStream(), null); + keystores.add(keystore); + } + catch (Exception x) + { + error(url, in, x.toString()); + } + } + else if (in.sval.equalsIgnoreCase("grant")) + { + if (state != STATE_BEGIN) + error(url, in, "extraneous grant keyword"); + state = STATE_GRANT; + } + else if (in.sval.equalsIgnoreCase("signedBy")) + { + if (state != STATE_GRANT && state != STATE_PERMS) + error(url, in, "spurious 'signedBy'"); + if (keystores.isEmpty()) + error(url, in, "'signedBy' with no keystores"); + tok = in.nextToken(); + if (tok != '"' && tok != '\'') + error(url, in, "expecting signedBy name"); + StringTokenizer st = new StringTokenizer(in.sval, ","); + while (st.hasMoreTokens()) + { + String alias = st.nextToken(); + for (Iterator it = keystores.iterator(); it.hasNext(); ) + { + KeyStore keystore = (KeyStore) it.next(); + try + { + if (keystore.isCertificateEntry(alias)) + currentCerts.add(keystore.getCertificate(alias)); + } + catch (KeyStoreException kse) + { + error(url, in, kse.toString()); + } + } + } + tok = in.nextToken(); + if (tok != ',') + { + if (state != STATE_GRANT) + error(url, in, "spurious ','"); + in.pushBack(); + } + } + else if (in.sval.equalsIgnoreCase("codeBase")) + { + if (state != STATE_GRANT) + error(url, in, "spurious 'codeBase'"); + tok = in.nextToken(); + if (tok != '"' && tok != '\'') + error(url, in, "expecting code base URL"); + String base = expand(in.sval); + if (File.separatorChar != '/') + base = base.replace(File.separatorChar, '/'); + try + { + currentBase = new URL(base); + } + catch (MalformedURLException mue) + { + error(url, in, mue.toString()); + } + tok = in.nextToken(); + if (tok != ',') + in.pushBack(); + } + else if (in.sval.equalsIgnoreCase("principal")) + { + if (state != STATE_GRANT) + error(url, in, "spurious 'principal'"); + tok = in.nextToken(); + if (tok == StreamTokenizer.TT_WORD) + { + tok = in.nextToken(); + if (tok != '"' && tok != '\'') + error(url, in, "expecting principal name"); + String name = in.sval; + Principal p = null; + try + { + Class pclass = Class.forName(in.sval); + Constructor c = + pclass.getConstructor(new Class[] { String.class }); + p = (Principal) c.newInstance(new Object[] { name }); + } + catch (Exception x) + { + error(url, in, x.toString()); + } + for (Iterator it = keystores.iterator(); it.hasNext(); ) + { + KeyStore ks = (KeyStore) it.next(); + try + { + for (Enumeration e = ks.aliases(); e.hasMoreElements(); ) + { + String alias = (String) e.nextElement(); + if (ks.isCertificateEntry(alias)) + { + Certificate cert = ks.getCertificate(alias); + if (!(cert instanceof X509Certificate)) + continue; + if (p.equals(((X509Certificate) cert).getSubjectDN()) || + p.equals(((X509Certificate) cert).getSubjectX500Principal())) + currentCerts.add(cert); + } + } + } + catch (KeyStoreException kse) + { + error(url, in, kse.toString()); + } + } + } + else if (tok == '"' || tok == '\'') + { + String alias = in.sval; + for (Iterator it = keystores.iterator(); it.hasNext(); ) + { + KeyStore ks = (KeyStore) it.next(); + try + { + if (ks.isCertificateEntry(alias)) + currentCerts.add(ks.getCertificate(alias)); + } + catch (KeyStoreException kse) + { + error(url, in, kse.toString()); + } + } + } + else + error(url, in, "expecting principal"); + tok = in.nextToken(); + if (tok != ',') + in.pushBack(); + } + else if (in.sval.equalsIgnoreCase("permission")) + { + if (state != STATE_PERMS) + error(url, in, "spurious 'permission'"); + tok = in.nextToken(); + if (tok != StreamTokenizer.TT_WORD) + error(url, in, "expecting permission class name"); + String className = in.sval; + Class clazz = null; + try + { + clazz = Class.forName(className); + } + catch (ClassNotFoundException cnfe) + { + } + tok = in.nextToken(); + if (tok == ';') + { + if (clazz == null) + { + currentPerms.add(new UnresolvedPermission(className, + null, null, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()]))); + continue; + } + try + { + currentPerms.add((Permission) clazz.newInstance()); + } + catch (Exception x) + { + error(url, in, x.toString()); + } + continue; + } + if (tok != '"' && tok != '\'') + error(url, in, "expecting permission target"); + String target = expand(in.sval); + tok = in.nextToken(); + if (tok == ';') + { + if (clazz == null) + { + currentPerms.add(new UnresolvedPermission(className, + target, null, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()]))); + continue; + } + try + { + Constructor c = + clazz.getConstructor(new Class[] { String.class }); + currentPerms.add((Permission) c.newInstance( + new Object[] { target })); + } + catch (Exception x) + { + error(url, in, x.toString()); + } + continue; + } + if (tok != ',') + error(url, in, "expecting ','"); + tok = in.nextToken(); + if (tok == StreamTokenizer.TT_WORD) + { + if (!in.sval.equalsIgnoreCase("signedBy")) + error(url, in, "expecting 'signedBy'"); + try + { + Constructor c = + clazz.getConstructor(new Class[] { String.class }); + currentPerms.add((Permission) c.newInstance( + new Object[] { target })); + } + catch (Exception x) + { + error(url, in, x.toString()); + } + in.pushBack(); + continue; + } + if (tok != '"' && tok != '\'') + error(url, in, "expecting permission action"); + String action = in.sval; + if (clazz == null) + { + currentPerms.add(new UnresolvedPermission(className, + target, action, (Certificate[]) currentCerts.toArray(new Certificate[currentCerts.size()]))); + continue; + } + else + { + try + { + Constructor c = clazz.getConstructor( + new Class[] { String.class, String.class }); + currentPerms.add((Permission) c.newInstance( + new Object[] { target, action })); + } + catch (Exception x) + { + error(url, in, x.toString()); + } + } + tok = in.nextToken(); + if (tok != ';' && tok != ',') + error(url, in, "expecting ';' or ','"); + } + } + } + + /** + * Expand all instances of "${property-name}" into + * System.getProperty("property-name"). + */ + private static String expand(final String s) + { + final CPStringBuilder result = new CPStringBuilder(); + final CPStringBuilder prop = new CPStringBuilder(); + int state = 0; + for (int i = 0; i < s.length(); i++) + { + switch (state) + { + case 0: + if (s.charAt(i) == '$') + state = 1; + else + result.append(s.charAt(i)); + break; + case 1: + if (s.charAt(i) == '{') + state = 2; + else + { + state = 0; + result.append('$').append(s.charAt(i)); + } + break; + case 2: + if (s.charAt(i) == '}') + { + String p = prop.toString(); + if (p.equals("/")) + p = "file.separator"; + p = System.getProperty(p); + if (p == null) + p = ""; + result.append(p); + prop.setLength(0); + state = 0; + } + else + prop.append(s.charAt(i)); + break; + } + } + if (state != 0) + result.append('$').append('{').append(prop); + return result.toString(); + } + + /** + * I miss macros. + */ + private static void error(URL base, StreamTokenizer in, String msg) + throws IOException + { + throw new IOException(base+":"+in.lineno()+": "+msg); + } +} diff --git a/libjava/classpath/gnu/java/security/Properties.java b/libjava/classpath/gnu/java/security/Properties.java new file mode 100644 index 000000000..2213bde06 --- /dev/null +++ b/libjava/classpath/gnu/java/security/Properties.java @@ -0,0 +1,348 @@ +/* Properties.java -- run-time configuration properties. + Copyright (C) 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security; + +import gnu.java.security.Configuration; + +import java.io.FileInputStream; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.util.HashMap; +import java.util.PropertyPermission; +import java.util.logging.Logger; + +/** + * A global object containing build-specific properties that affect the + * behaviour of the generated binaries from this library. + */ +public final class Properties +{ + private static final Logger log = Logger.getLogger(Properties.class.getName()); + + public static final String VERSION = "gnu.crypto.version"; + + public static final String PROPERTIES_FILE = "gnu.crypto.properties.file"; + + public static final String REPRODUCIBLE_PRNG = "gnu.crypto.with.reproducible.prng"; + + public static final String CHECK_WEAK_KEYS = "gnu.crypto.with.check.for.weak.keys"; + + public static final String DO_RSA_BLINDING = "gnu.crypto.with.rsa.blinding"; + + private static final String TRUE = Boolean.TRUE.toString(); + + private static final String FALSE = Boolean.FALSE.toString(); + + private static final HashMap props = new HashMap(); + + private static Properties singleton = null; + + private boolean reproducible = false; + + private boolean checkForWeakKeys = true; + + private boolean doRSABlinding = true; + + /** Trivial constructor to enforce Singleton pattern. */ + private Properties() + { + super(); + init(); + } + + /** + * Returns the string representation of the library global configuration + * property with the designated key. + * + * @param key the case-insensitive, non-null and non-empty name of a + * configuration property. + * @return the string representation of the designated property, or + * null if such property is not yet set, or + * key is empty. + */ + public static final synchronized String getProperty(String key) + { + if (key == null) + return null; + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(key, "read")); + key = key.trim().toLowerCase(); + if ("".equals(key)) + return null; + return (String) props.get(key); + } + + /** + * Sets the value of a designated library global configuration property, to a + * string representation of what should be a legal value. + * + * @param key the case-insensitive, non-null and non-empty name of a + * configuration property. + * @param value the non-null, non-empty string representation of a legal value + * of the configuration property named by key. + */ + public static final synchronized void setProperty(String key, String value) + { + if (key == null || value == null) + return; + key = key.trim().toLowerCase(); + if ("".equals(key)) + return; + if (key.equals(VERSION)) + return; + value = value.trim(); + if ("".equals(value)) + return; + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(key, "write")); + if (key.equals(REPRODUCIBLE_PRNG) + && (value.equalsIgnoreCase(TRUE) || value.equalsIgnoreCase(FALSE))) + setReproducible(Boolean.valueOf(value).booleanValue()); + else if (key.equals(CHECK_WEAK_KEYS) + && (value.equalsIgnoreCase(TRUE) || value.equalsIgnoreCase(FALSE))) + setCheckForWeakKeys(Boolean.valueOf(value).booleanValue()); + else if (key.equals(DO_RSA_BLINDING) + && (value.equalsIgnoreCase(TRUE) || value.equalsIgnoreCase(FALSE))) + setDoRSABlinding(Boolean.valueOf(value).booleanValue()); + else + props.put(key, value); + } + + /** + * A convenience method that returns, as a boolean, the library global + * configuration property indicating if the default Pseudo Random Number + * Generator produces, or not, the same bit stream when instantiated. + * + * @return true if the default PRNG produces the same bit + * stream with every VM instance. Returns false if the + * default PRNG is seeded with the time of day of its first + * invocation. + */ + public static final synchronized boolean isReproducible() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(REPRODUCIBLE_PRNG, "read")); + return instance().reproducible; + } + + /** + * A convenience method that returns, as a boolean, the library global + * configuration property indicating if the implementations of symmetric key + * block ciphers check, or not, for possible/potential weak and semi-weak keys + * that may be produced in the course of generating round encryption and/or + * decryption keys. + * + * @return true if the cipher implementations check for weak + * and semi-weak keys. Returns false if the cipher + * implementations do not check for weak or semi-weak keys. + */ + public static final synchronized boolean checkForWeakKeys() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(CHECK_WEAK_KEYS, "read")); + return instance().checkForWeakKeys; + } + + /** + * A convenience method that returns, as a boolean, the library global + * configuration property indicating if RSA decryption (RSADP primitive), + * does, or not, blinding against timing attacks. + * + * @return true if the RSA decryption primitive includes a + * blinding operation. Returns false if the RSA + * decryption primitive does not include the additional blinding + * operation. + */ + public static final synchronized boolean doRSABlinding() + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(DO_RSA_BLINDING, "read")); + return instance().doRSABlinding; + } + + /** + * A convenience method to set the global property for reproducibility of the + * default PRNG bit stream output. + * + * @param value if true then the default PRNG bit stream output + * is the same with every invocation of the VM. + */ + public static final synchronized void setReproducible(final boolean value) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(REPRODUCIBLE_PRNG, "write")); + instance().reproducible = value; + props.put(REPRODUCIBLE_PRNG, String.valueOf(value)); + } + + /** + * A convenience method to set the global property for checking for weak and + * semi-weak cipher keys. + * + * @param value if true then the cipher implementations will + * invoke additional checks for weak and semi-weak key values that + * may get generated. + */ + public static final synchronized void setCheckForWeakKeys(final boolean value) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(CHECK_WEAK_KEYS, "write")); + instance().checkForWeakKeys = value; + props.put(CHECK_WEAK_KEYS, String.valueOf(value)); + } + + /** + * A convenience method to set the global property fo adding a blinding + * operation when executing the RSA decryption primitive. + * + * @param value if true then the code for performing the RSA + * decryption primitive will include a blinding operation. + */ + public static final synchronized void setDoRSABlinding(final boolean value) + { + SecurityManager sm = System.getSecurityManager(); + if (sm != null) + sm.checkPermission(new PropertyPermission(DO_RSA_BLINDING, "write")); + instance().doRSABlinding = value; + props.put(DO_RSA_BLINDING, String.valueOf(value)); + } + + private static final synchronized Properties instance() + { + if (singleton == null) + singleton = new Properties(); + return singleton; + } + + private void init() + { + // default values + props.put(REPRODUCIBLE_PRNG, (reproducible ? "true" : "false")); + props.put(CHECK_WEAK_KEYS, (checkForWeakKeys ? "true" : "false")); + props.put(DO_RSA_BLINDING, (doRSABlinding ? "true" : "false")); + // 1. allow site-wide override by reading a properties file + String propFile = null; + try + { + propFile = (String) AccessController.doPrivileged(new PrivilegedAction() + { + public Object run() + { + return System.getProperty(PROPERTIES_FILE); + } + }); + } + catch (SecurityException se) + { + if (Configuration.DEBUG) + log.fine("Reading property " + PROPERTIES_FILE + " not allowed. Ignored."); + } + if (propFile != null) + { + try + { + final java.util.Properties temp = new java.util.Properties(); + final FileInputStream fin = new FileInputStream(propFile); + temp.load(fin); + temp.list(System.out); + props.putAll(temp); + } + catch (IOException ioe) + { + if (Configuration.DEBUG) + log.fine("IO error reading " + propFile + ": " + ioe.getMessage()); + } + catch (SecurityException se) + { + if (Configuration.DEBUG) + log.fine("Security error reading " + propFile + ": " + + se.getMessage()); + } + } + // 2. allow vm-specific override by allowing -D options in launcher + handleBooleanProperty(REPRODUCIBLE_PRNG); + handleBooleanProperty(CHECK_WEAK_KEYS); + handleBooleanProperty(DO_RSA_BLINDING); + // re-sync the 'known' properties + reproducible = Boolean.valueOf((String) props.get(REPRODUCIBLE_PRNG)).booleanValue(); + checkForWeakKeys = Boolean.valueOf((String) props.get(CHECK_WEAK_KEYS)).booleanValue(); + doRSABlinding = Boolean.valueOf((String) props.get(DO_RSA_BLINDING)).booleanValue(); + // This does not change. + props.put(VERSION, Registry.VERSION_STRING); + } + + private void handleBooleanProperty(final String name) + { + String s = null; + try + { + s = System.getProperty(name); + } + catch (SecurityException x) + { + if (Configuration.DEBUG) + log.fine("SecurityManager forbids reading system properties. Ignored"); + } + if (s != null) + { + s = s.trim().toLowerCase(); + // we have to test for explicit "true" or "false". anything else may + // hide valid value set previously + if (s.equals(TRUE) || s.equals(FALSE)) + { + if (Configuration.DEBUG) + log.fine("Setting " + name + " to '" + s + "'"); + props.put(name, s); + } + else + { + if (Configuration.DEBUG) + log.fine("Invalid value for -D" + name + ": " + s + ". Ignored"); + } + } + } +} diff --git a/libjava/classpath/gnu/java/security/Registry.java b/libjava/classpath/gnu/java/security/Registry.java new file mode 100644 index 000000000..4ce5044ab --- /dev/null +++ b/libjava/classpath/gnu/java/security/Registry.java @@ -0,0 +1,465 @@ +/* Registry.java -- + Copyright (C) 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security; + +/** + * A placeholder for names and literals used throughout this + * library. + */ +public interface Registry +{ + /** The name of our Providers. */ + String GNU_SECURITY = "GNU"; + String GNU_CRYPTO = "GNU-CRYPTO"; + String GNU_SASL = "GNU-SASL"; + + /** Our version number. */ + String VERSION_STRING = "2.1.0"; + + // Names of properties to use in Maps when initialising primitives ......... + + // Symmetric block cipher algorithms and synonyms........................... + + String ANUBIS_CIPHER = "anubis"; + + String BLOWFISH_CIPHER = "blowfish"; + + String DES_CIPHER = "des"; + + String KHAZAD_CIPHER = "khazad"; + + String RIJNDAEL_CIPHER = "rijndael"; + + String SERPENT_CIPHER = "serpent"; + + String SQUARE_CIPHER = "square"; + + String TRIPLEDES_CIPHER = "tripledes"; + + String TWOFISH_CIPHER = "twofish"; + + String CAST5_CIPHER = "cast5"; + + String NULL_CIPHER = "null"; + + /** AES is synonymous to Rijndael for 128-bit block size only. */ + String AES_CIPHER = "aes"; + + /** TripleDES is also known as DESede. */ + String DESEDE_CIPHER = "desede"; + + /** CAST5 is also known as CAST-128. */ + String CAST128_CIPHER = "cast128"; + + String CAST_128_CIPHER = "cast-128"; + + // Key Wrapping Algorithm names and synonyms ............................... + + String KWA_PREFIX = "kw-"; + String AES_KWA = KWA_PREFIX + AES_CIPHER; + String AES128_KWA = AES_KWA + "128"; + String AES192_KWA = AES_KWA + "192"; + String AES256_KWA = AES_KWA + "256"; + String RIJNDAEL_KWA = KWA_PREFIX + RIJNDAEL_CIPHER; + + String TRIPLEDES_KWA = KWA_PREFIX + TRIPLEDES_CIPHER; + String DESEDE_KWA = KWA_PREFIX + DESEDE_CIPHER; + + // Message digest algorithms and synonyms................................... + + String WHIRLPOOL_HASH = "whirlpool"; + + String RIPEMD128_HASH = "ripemd128"; + + String RIPEMD160_HASH = "ripemd160"; + + String SHA160_HASH = "sha-160"; + + String SHA256_HASH = "sha-256"; + + String SHA384_HASH = "sha-384"; + + String SHA512_HASH = "sha-512"; + + String TIGER_HASH = "tiger"; + + String HAVAL_HASH = "haval"; + + String MD5_HASH = "md5"; + + String MD4_HASH = "md4"; + + String MD2_HASH = "md2"; + + /** RIPEMD-128 is synonymous to RIPEMD128. */ + String RIPEMD_128_HASH = "ripemd-128"; + + /** RIPEMD-160 is synonymous to RIPEMD160. */ + String RIPEMD_160_HASH = "ripemd-160"; + + /** SHA-1 is synonymous to SHA-160. */ + String SHA_1_HASH = "sha-1"; + + /** SHA1 is synonymous to SHA-160. */ + String SHA1_HASH = "sha1"; + + /** SHA is synonymous to SHA-160. */ + String SHA_HASH = "sha"; + + // Symmetric block cipher modes of operations............................... + + /** Electronic CodeBook mode. */ + String ECB_MODE = "ecb"; + + /** Counter (NIST) mode. */ + String CTR_MODE = "ctr"; + + /** Integer Counter Mode (David McGrew). */ + String ICM_MODE = "icm"; + + /** Output Feedback Mode (NIST). */ + String OFB_MODE = "ofb"; + + /** Cipher block chaining mode (NIST). */ + String CBC_MODE = "cbc"; + + /** Cipher feedback mode (NIST). */ + String CFB_MODE = "cfb"; + + /** Authenticated-Encrypted mode. */ + String EAX_MODE = "eax"; + + // Padding scheme names and synonyms........................................ + + /** PKCS#5 padding scheme. */ + String PKCS5_PAD = "pkcs5"; + + /** PKCS#7 padding scheme. */ + String PKCS7_PAD = "pkcs7"; + + /** Trailing Bit Complement padding scheme. */ + String TBC_PAD = "tbc"; + + /** EME-PKCS1-v1_5 padding as described in section 7.2 in RFC-3447. */ + String EME_PKCS1_V1_5_PAD = "eme-pkcs1-v1.5"; + + /** SSLv3 padding scheme. */ + String SSL3_PAD = "ssl3"; + + /** TLSv1 padding scheme. */ + String TLS1_PAD = "tls1"; + + /** ISO 10126-2 padding scheme. */ + String ISO10126_PAD = "iso10126"; + + // Pseudo-random number generators.......................................... + + /** (Apparently) RC4 keystream PRNG. */ + String ARCFOUR_PRNG = "arcfour"; + + /** We use "rc4" as an alias for "arcfour". */ + String RC4_PRNG = "rc4"; + + /** PRNG based on David McGrew's Integer Counter Mode. */ + String ICM_PRNG = "icm"; + + /** PRNG based on a designated hash function. */ + String MD_PRNG = "md"; + + /** PRNG based on UMAC's Key Derivation Function. */ + String UMAC_PRNG = "umac-kdf"; + + /** + * PRNG based on PBKDF2 from PKCS #5 v.2. This is suffixed with the name + * of a MAC to be used as a PRF. + */ + String PBKDF2_PRNG_PREFIX = "pbkdf2-"; + + /** The continuously-seeded pseudo-random number generator. */ + String CSPRNG_PRNG = "csprng"; + + /** The Fortuna PRNG. */ + String FORTUNA_PRNG = "fortuna"; + + /** The Fortuna generator PRNG. */ + String FORTUNA_GENERATOR_PRNG = "fortuna-generator"; + + // Asymmetric keypair generators............................................ + + String DSS_KPG = "dss"; + + String RSA_KPG = "rsa"; + + String DH_KPG = "dh"; + + String SRP_KPG = "srp"; + + /** DSA is synonymous to DSS. */ + String DSA_KPG = "dsa"; + + // Signature-with-appendix schemes.......................................... + + String DSS_SIG = "dss"; + + String RSA_SIG_PREFIX = "rsa-"; + + String RSA_PSS_ENCODING = "pss"; + + String RSA_PSS_SIG = RSA_SIG_PREFIX + RSA_PSS_ENCODING; + + String RSA_PKCS1_V1_5_ENCODING = "pkcs1-v1.5"; + + String RSA_PKCS1_V1_5_SIG = RSA_SIG_PREFIX + RSA_PKCS1_V1_5_ENCODING; + + /** DSA is synonymous to DSS. */ + String DSA_SIG = "dsa"; + + // Key agreement protocols ................................................. + + String DH_KA = "dh"; + + String ELGAMAL_KA = "elgamal"; + + String SRP6_KA = "srp6"; + + String SRP_SASL_KA = "srp-sasl"; + + String SRP_TLS_KA = "srp-tls"; + + // Keyed-Hash Message Authentication Code .................................. + + /** Name prefix of every HMAC implementation. */ + String HMAC_NAME_PREFIX = "hmac-"; + + // Other MAC algorithms .................................................... + + /** The One-key CBC MAC. */ + String OMAC_PREFIX = "omac-"; + + /** Message Authentication Code using Universal Hashing (Ted Krovetz). */ + String UHASH32 = "uhash32"; + + String UMAC32 = "umac32"; + + /** The Truncated Multi-Modular Hash Function -v1 (David McGrew). */ + String TMMH16 = "tmmh16"; + + // String TMMH32 = "tmmh32"; + + // Format IDs used to identify how we externalise asymmetric keys .......... + // fully-qualified names of the supported codecs + String RAW_ENCODING = "gnu.crypto.raw.format"; + String X509_ENCODING = "gnu.crypto.x509.format"; + String PKCS8_ENCODING = "gnu.crypto.pkcs8.format"; + String ASN1_ENCODING = "gnu.crypto.asn1.format"; + + // short names of the same. used by JCE adapters + String RAW_ENCODING_SHORT_NAME = "RAW"; + String X509_ENCODING_SORT_NAME = "X.509"; + String PKCS8_ENCODING_SHORT_NAME = "PKCS#8"; + String ASN1_ENCODING_SHORT_NAME = "ASN.1"; + + // unique identifiers of the same + int RAW_ENCODING_ID = 1; + int X509_ENCODING_ID = 2; + int PKCS8_ENCODING_ID = 3; + int ASN1_ENCODING_ID = 4; + + // OID strings used in encoding/decoding keys + String DSA_OID_STRING = "1.2.840.10040.4.1"; + String RSA_OID_STRING = "1.2.840.113549.1.1.1"; + String DH_OID_STRING = "1.2.840.10046.2.1"; + + // Magic bytes we generate/expect in externalised asymmetric keys .......... + // the four bytes represent G (0x47) for GNU, 1 (0x01) for Raw format, + // D (0x44) for DSS, R (0x52) for RSA, H (0x48) for Diffie-Hellman, or S + // (0x53) for SRP-6, and finally P (0x50) for Public, p (0x70) for private, + // or S (0x53) for signature. + byte[] MAGIC_RAW_DSS_PUBLIC_KEY = new byte[] { + 0x47, RAW_ENCODING_ID, 0x44, 0x50 }; + + byte[] MAGIC_RAW_DSS_PRIVATE_KEY = new byte[] { + 0x47, RAW_ENCODING_ID, 0x44, 0x70 }; + + byte[] MAGIC_RAW_DSS_SIGNATURE = new byte[] { + 0x47, RAW_ENCODING_ID, 0x44, 0x53 }; + + byte[] MAGIC_RAW_RSA_PUBLIC_KEY = new byte[] { + 0x47, RAW_ENCODING_ID, 0x52, 0x50 }; + + byte[] MAGIC_RAW_RSA_PRIVATE_KEY = new byte[] { + 0x47, RAW_ENCODING_ID, 0x52, 0x70 }; + + byte[] MAGIC_RAW_RSA_PSS_SIGNATURE = new byte[] { + 0x47, RAW_ENCODING_ID, 0x52, 0x53 }; + + byte[] MAGIC_RAW_RSA_PKCS1V1_5_SIGNATURE = new byte[] { + 0x47, RAW_ENCODING_ID, 0x52, 0x54 }; + + byte[] MAGIC_RAW_DH_PUBLIC_KEY = new byte[] { + 0x47, RAW_ENCODING_ID, 0x48, 0x50 }; + + byte[] MAGIC_RAW_DH_PRIVATE_KEY = new byte[] { + 0x47, RAW_ENCODING_ID, 0x48, 0x70 }; + + byte[] MAGIC_RAW_SRP_PUBLIC_KEY = new byte[] { + 0x47, RAW_ENCODING_ID, 0x53, 0x50 }; + + byte[] MAGIC_RAW_SRP_PRIVATE_KEY = new byte[] { + 0x47, RAW_ENCODING_ID, 0x53, 0x70 }; + + // SASL Property names ..................................................... + + String SASL_PREFIX = "gnu.crypto.sasl"; + + /** Name of username property. */ + String SASL_USERNAME = SASL_PREFIX + ".username"; + + /** Name of password property. */ + String SASL_PASSWORD = SASL_PREFIX + ".password"; + + /** Name of authentication information provider packages. */ + String SASL_AUTH_INFO_PROVIDER_PKGS = SASL_PREFIX + ".auth.info.provider.pkgs"; + + /** SASL authorization ID. */ + String SASL_AUTHORISATION_ID = SASL_PREFIX + ".authorisation.ID"; + + /** SASL protocol. */ + String SASL_PROTOCOL = SASL_PREFIX + ".protocol"; + + /** SASL Server name. */ + String SASL_SERVER_NAME = SASL_PREFIX + ".server.name"; + + /** SASL Callback handler. */ + String SASL_CALLBACK_HANDLER = SASL_PREFIX + ".callback.handler"; + + /** SASL channel binding. */ + String SASL_CHANNEL_BINDING = SASL_PREFIX + ".channel.binding"; + + // SASL data element size limits ........................................... + + /** The size limit, in bytes, of a SASL OS (Octet Sequence) element. */ + int SASL_ONE_BYTE_MAX_LIMIT = 255; + + /** + * The size limit, in bytes, of both a SASL MPI (Multi-Precision Integer) + * element and a SASL Text element. + */ + int SASL_TWO_BYTE_MAX_LIMIT = 65535; + + /** The size limit, in bytes, of a SASL EOS (Extended Octet Sequence) element. */ + int SASL_FOUR_BYTE_MAX_LIMIT = 2147483383; + + /** The size limit, in bytes, of a SASL Buffer. */ + int SASL_BUFFER_MAX_LIMIT = 2147483643; + + // Canonical names of SASL mechanisms ...................................... + + String SASL_ANONYMOUS_MECHANISM = "ANONYMOUS"; + + String SASL_CRAM_MD5_MECHANISM = "CRAM-MD5"; + + String SASL_PLAIN_MECHANISM = "PLAIN"; + + String SASL_SRP_MECHANISM = "SRP"; + + // Canonical names of Integrity Protection algorithms ...................... + + String SASL_HMAC_MD5_IALG = "HMACwithMD5"; + + String SASL_HMAC_SHA_IALG = "HMACwithSHA"; + + // Quality Of Protection string representations ............................ + + /** authentication only. */ + String QOP_AUTH = "auth"; + + /** authentication plus integrity protection. */ + String QOP_AUTH_INT = "auth-int"; + + /** authentication plus integrity and confidentiality protection. */ + String QOP_AUTH_CONF = "auth-conf"; + + // SASL mechanism strength string representation ........................... + + String STRENGTH_HIGH = "high"; + + String STRENGTH_MEDIUM = "medium"; + + String STRENGTH_LOW = "low"; + + // SASL Server Authentication requirement .................................. + + /** Server must authenticate to the client. */ + String SERVER_AUTH_TRUE = "true"; + + /** Server does not need to, or cannot, authenticate to the client. */ + String SERVER_AUTH_FALSE = "false"; + + // SASL mechanism reuse capability ......................................... + + String REUSE_TRUE = "true"; + + String REUSE_FALSE = "false"; + + // Keyrings ............................................................... + + byte[] GKR_MAGIC = new byte[] { 0x47, 0x4b, 0x52, 0x01 }; + + // Ring usage fields. + int GKR_PRIVATE_KEYS = 1 << 0; + + int GKR_PUBLIC_CREDENTIALS = 1 << 1; + + int GKR_CERTIFICATES = 1 << 2; + + // HMac types. + int GKR_HMAC_MD5_128 = 0; + + int GKR_HMAC_SHA_160 = 1; + + int GKR_HMAC_MD5_96 = 2; + + int GKR_HMAC_SHA_96 = 3; + + // Cipher types. + int GKR_CIPHER_AES_128_OFB = 0; + + int GKR_CIPHER_AES_128_CBC = 1; +} diff --git a/libjava/classpath/gnu/java/security/Requires.java b/libjava/classpath/gnu/java/security/Requires.java new file mode 100644 index 000000000..6b52bd168 --- /dev/null +++ b/libjava/classpath/gnu/java/security/Requires.java @@ -0,0 +1,59 @@ +/* Requires.java -- mark methods as requiring permission. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security; + +import java.lang.annotation.Documented; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.CLASS; +import java.security.Permission; + +/** + * + * + * @author Casey Marshall (csm@gnu.org) + */ +@Documented @Retention(CLASS) @Target(METHOD) +public @interface Requires +{ + Class permissionClass(); + String target(); + String action(); +} diff --git a/libjava/classpath/gnu/java/security/action/GetPropertyAction.java b/libjava/classpath/gnu/java/security/action/GetPropertyAction.java new file mode 100644 index 000000000..7295d8d5a --- /dev/null +++ b/libjava/classpath/gnu/java/security/action/GetPropertyAction.java @@ -0,0 +1,89 @@ +/* GetPropertyAction.java + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.security.action; + +import java.security.PrivilegedAction; + +/** + * PrivilegedAction implementation that calls System.getProperty() with + * the property name passed to its constructor. + * + * Example of use: + * + * GetPropertyAction action = new GetPropertyAction("http.proxyPort"); + * String port = AccessController.doPrivileged(action); + * + */ +public class GetPropertyAction implements PrivilegedAction +{ + String name; + String value = null; + + public GetPropertyAction() + { + } + + public GetPropertyAction(String propName) + { + setParameters(propName); + } + + public GetPropertyAction(String propName, String defaultValue) + { + setParameters(propName, defaultValue); + } + + public String run() + { + return System.getProperty(name, value); + } + + public GetPropertyAction setParameters(String propName) + { + this.name = propName; + this.value = null; + return this; + } + + public GetPropertyAction setParameters(String propName, String defaultValue) + { + this.name = propName; + this.value = defaultValue; + return this; + } +} diff --git a/libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java b/libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java new file mode 100644 index 000000000..ac928ca33 --- /dev/null +++ b/libjava/classpath/gnu/java/security/action/GetSecurityPropertyAction.java @@ -0,0 +1,93 @@ +/* GetSecurityPropertyAction.java + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.security.action; + +import java.security.PrivilegedAction; +import java.security.Security; + +/** + * PrivilegedAction implementation that calls Security.getProperty() + * with the property name passed to its constructor. + * + * Example of use: + * + * GetSecurityPropertyAction action = new GetSecurityPropertyAction("javax.net.ssl.trustStorePassword"); + * String passwd = AccessController.doPrivileged(action); + * + */ +public class GetSecurityPropertyAction implements PrivilegedAction +{ + private String name; + private String value; + + public GetSecurityPropertyAction() + { + } + + public GetSecurityPropertyAction(String propName) + { + setParameters(propName); + } + + public GetSecurityPropertyAction(String propName, String defaultValue) + { + setParameters(propName, defaultValue); + } + + public GetSecurityPropertyAction setParameters(String propName) + { + this.name = propName; + this.value = null; + return this; + } + + public GetSecurityPropertyAction setParameters(String propName, String defaultValue) + { + this.name = propName; + this.value = defaultValue; + return this; + } + + public String run() + { + String val = Security.getProperty(name); + if (val == null) + val = value; + return val; + } +} diff --git a/libjava/classpath/gnu/java/security/action/SetAccessibleAction.java b/libjava/classpath/gnu/java/security/action/SetAccessibleAction.java new file mode 100644 index 000000000..d3e3c0f90 --- /dev/null +++ b/libjava/classpath/gnu/java/security/action/SetAccessibleAction.java @@ -0,0 +1,77 @@ +/* SetAccessibleAction.java + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.security.action; + +import java.lang.reflect.AccessibleObject; +import java.security.PrivilegedAction; + +/** + * PrivilegedAction implementation that calls setAccessible(true) on the + * AccessibleObject passed to its constructor. + * + * Example of use: + * + * Field dataField = cl.getDeclaredField("data"); + * AccessController.doPrivileged(new SetAccessibleAction(dataField)); + * + */ +public class SetAccessibleAction implements PrivilegedAction +{ + AccessibleObject member; + + public SetAccessibleAction() + { + } + + public SetAccessibleAction(AccessibleObject member) + { + this.member = member; + } + + public Object run() + { + member.setAccessible(true); + return null; + } + + public SetAccessibleAction setMember(AccessibleObject member) + { + this.member = member; + return this; + } +} diff --git a/libjava/classpath/gnu/java/security/action/package.html b/libjava/classpath/gnu/java/security/action/package.html new file mode 100644 index 000000000..fc3dfa229 --- /dev/null +++ b/libjava/classpath/gnu/java/security/action/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security.action + + +

+ + + diff --git a/libjava/classpath/gnu/java/security/ber/BER.java b/libjava/classpath/gnu/java/security/ber/BER.java new file mode 100644 index 000000000..7efb1bf90 --- /dev/null +++ b/libjava/classpath/gnu/java/security/ber/BER.java @@ -0,0 +1,46 @@ +/* BER.java -- basic encoding rules (BER) constants. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.ber; + +import gnu.java.security.der.DER; + +public interface BER extends DER +{ + BERValue END_OF_SEQUENCE = new BERValue(0, null); +} diff --git a/libjava/classpath/gnu/java/security/ber/BEREncodingException.java b/libjava/classpath/gnu/java/security/ber/BEREncodingException.java new file mode 100644 index 000000000..aad10932c --- /dev/null +++ b/libjava/classpath/gnu/java/security/ber/BEREncodingException.java @@ -0,0 +1,54 @@ +/* BEREncodingException.java --- BER Encoding Exception + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.ber; + +import gnu.java.security.der.DEREncodingException; + +public class BEREncodingException extends DEREncodingException +{ + public BEREncodingException() + { + super (); + } + + public BEREncodingException (String msg) + { + super (msg); + } +} diff --git a/libjava/classpath/gnu/java/security/ber/BERReader.java b/libjava/classpath/gnu/java/security/ber/BERReader.java new file mode 100644 index 000000000..53a3f3ee9 --- /dev/null +++ b/libjava/classpath/gnu/java/security/ber/BERReader.java @@ -0,0 +1,103 @@ +/* BERReader.java -- basic encoding rules (BER) reader. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.ber; + +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; + +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; + +public class BERReader extends DERReader implements BER +{ + + /** + * Create a new DER reader from a byte array. + * + * @param in The encoded bytes. + */ + public BERReader(byte[] in) + { + super(in); + } + + public BERReader (byte[] in, int off, int len) + { + super(in, off, len); + } + + /** + * Create a new DER readed from an input stream. + * + * @param in The encoded bytes. + */ + public BERReader(InputStream in) + { + super(in); + } + + public DERValue read() throws IOException + { + in.mark(2); + int tag = in.read(); + if (tag == -1) + throw new EOFException(); + int length = in.read(); + if (length == 0) + { + if (tag == 0) + return END_OF_SEQUENCE; + return new BERValue(tag, CONSTRUCTED_VALUE, new byte[] { (byte) tag, 0 }); + } + else + { + in.reset(); + return super.read(); + } + } + + public int peek() throws IOException + { + in.mark(1); + int ret = in.read(); + in.reset(); + return ret; + } +} diff --git a/libjava/classpath/gnu/java/security/ber/BERValue.java b/libjava/classpath/gnu/java/security/ber/BERValue.java new file mode 100644 index 000000000..aeaef39bf --- /dev/null +++ b/libjava/classpath/gnu/java/security/ber/BERValue.java @@ -0,0 +1,82 @@ +/* BERReader.java -- basic encoding rules (BER) value. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.ber; + +import gnu.java.security.der.DERValue; + +public class BERValue extends DERValue +{ + + private boolean indefinite; + + public BERValue(int tag, Object value, byte[] encoded) + { + super(tag, 0, value, encoded); + indefinite = true; + } + + public BERValue(int tag, int length, Object value, byte[] encoded) + { + super(tag, length, value, encoded); + } + + public BERValue(int tag, Object value) + { + super(tag, 0, value, null); + } + + public static boolean isIndefinite(DERValue value) + { + if (value instanceof BERValue) + return ((BERValue) value).getIndefinite(); + return false; + } + + public boolean getIndefinite() + { + return indefinite; + } + + public int getLength() + { + if (indefinite) + return 0; + return super.getLength(); + } +} diff --git a/libjava/classpath/gnu/java/security/ber/package.html b/libjava/classpath/gnu/java/security/ber/package.html new file mode 100644 index 000000000..348a83c20 --- /dev/null +++ b/libjava/classpath/gnu/java/security/ber/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security.ber + + +

+ + + diff --git a/libjava/classpath/gnu/java/security/der/BitString.java b/libjava/classpath/gnu/java/security/der/BitString.java new file mode 100644 index 000000000..ac10be22e --- /dev/null +++ b/libjava/classpath/gnu/java/security/der/BitString.java @@ -0,0 +1,332 @@ +/* BitString.java -- Java representation of the BIT STRING type. + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.der; + +import gnu.java.lang.CPStringBuilder; + +import java.math.BigInteger; +import java.util.Arrays; + +/** + * Immutable representation of a bit string, which is equivalent to a + * byte array except some number of the rightmost bits are ignored. For + * example, this could be the bit string: + * + *
   00010101 11101101 11010xxx
+ * + *

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

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

+ + + diff --git a/libjava/classpath/gnu/java/security/hash/BaseHash.java b/libjava/classpath/gnu/java/security/hash/BaseHash.java new file mode 100644 index 000000000..bab930f28 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/BaseHash.java @@ -0,0 +1,183 @@ +/* BaseHash.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +/** + * A base abstract class to facilitate hash implementations. + */ +public abstract class BaseHash + implements IMessageDigest +{ + /** The canonical name prefix of the hash. */ + protected String name; + + /** The hash (output) size in bytes. */ + protected int hashSize; + + /** The hash (inner) block size in bytes. */ + protected int blockSize; + + /** Number of bytes processed so far. */ + protected long count; + + /** Temporary input buffer. */ + protected byte[] buffer; + + /** + * Trivial constructor for use by concrete subclasses. + * + * @param name the canonical name prefix of this instance. + * @param hashSize the block size of the output in bytes. + * @param blockSize the block size of the internal transform. + */ + protected BaseHash(String name, int hashSize, int blockSize) + { + super(); + + this.name = name; + this.hashSize = hashSize; + this.blockSize = blockSize; + this.buffer = new byte[blockSize]; + + resetContext(); + } + + public String name() + { + return name; + } + + public int hashSize() + { + return hashSize; + } + + public int blockSize() + { + return blockSize; + } + + public void update(byte b) + { + // compute number of bytes still unhashed; ie. present in buffer + int i = (int) (count % blockSize); + count++; + buffer[i] = b; + if (i == (blockSize - 1)) + transform(buffer, 0); + } + + public void update(byte[] b) + { + update(b, 0, b.length); + } + + public void update(byte[] b, int offset, int len) + { + int n = (int) (count % blockSize); + count += len; + int partLen = blockSize - n; + int i = 0; + + if (len >= partLen) + { + System.arraycopy(b, offset, buffer, n, partLen); + transform(buffer, 0); + for (i = partLen; i + blockSize - 1 < len; i += blockSize) + transform(b, offset + i); + + n = 0; + } + + if (i < len) + System.arraycopy(b, offset + i, buffer, n, len - i); + } + + public byte[] digest() + { + byte[] tail = padBuffer(); // pad remaining bytes in buffer + update(tail, 0, tail.length); // last transform of a message + byte[] result = getResult(); // make a result out of context + + reset(); // reset this instance for future re-use + + return result; + } + + public void reset() + { // reset this instance for future re-use + count = 0L; + for (int i = 0; i < blockSize;) + buffer[i++] = 0; + + resetContext(); + } + + public abstract Object clone(); + + public abstract boolean selfTest(); + + /** + * Returns the byte array to use as padding before completing a hash + * operation. + * + * @return the bytes to pad the remaining bytes in the buffer before + * completing a hash operation. + */ + protected abstract byte[] padBuffer(); + + /** + * Constructs the result from the contents of the current context. + * + * @return the output of the completed hash operation. + */ + protected abstract byte[] getResult(); + + /** Resets the instance for future re-use. */ + protected abstract void resetContext(); + + /** + * The block digest transformation per se. + * + * @param in the blockSize long block, as an array of bytes to digest. + * @param offset the index where the data to digest is located within the + * input buffer. + */ + protected abstract void transform(byte[] in, int offset); +} diff --git a/libjava/classpath/gnu/java/security/hash/HashFactory.java b/libjava/classpath/gnu/java/security/hash/HashFactory.java new file mode 100644 index 000000000..1210ff4db --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/HashFactory.java @@ -0,0 +1,135 @@ +/* HashFactory.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory to instantiate message digest algorithm instances. + */ +public class HashFactory +{ + /** Trivial constructor to enforce Singleton pattern. */ + private HashFactory() + { + super(); + } + + /** + * Return an instance of a hash algorithm given its name. + * + * @param name the name of the hash algorithm. + * @return an instance of the hash algorithm, or null if none found. + * @exception InternalError if the implementation does not pass its self- + * test. + */ + public static IMessageDigest getInstance(String name) + { + if (name == null) + return null; + + name = name.trim(); + IMessageDigest result = null; + if (name.equalsIgnoreCase(Registry.WHIRLPOOL_HASH)) + result = new Whirlpool(); + else if (name.equalsIgnoreCase(Registry.RIPEMD128_HASH) + || name.equalsIgnoreCase(Registry.RIPEMD_128_HASH)) + result = new RipeMD128(); + else if (name.equalsIgnoreCase(Registry.RIPEMD160_HASH) + || name.equalsIgnoreCase(Registry.RIPEMD_160_HASH)) + result = new RipeMD160(); + else if (name.equalsIgnoreCase(Registry.SHA160_HASH) + || name.equalsIgnoreCase(Registry.SHA_1_HASH) + || name.equalsIgnoreCase(Registry.SHA1_HASH) + || name.equalsIgnoreCase(Registry.SHA_HASH)) + result = new Sha160(); + else if (name.equalsIgnoreCase(Registry.SHA256_HASH)) + result = new Sha256(); + else if (name.equalsIgnoreCase(Registry.SHA384_HASH)) + result = new Sha384(); + else if (name.equalsIgnoreCase(Registry.SHA512_HASH)) + result = new Sha512(); + else if (name.equalsIgnoreCase(Registry.TIGER_HASH)) + result = new Tiger(); + else if (name.equalsIgnoreCase(Registry.HAVAL_HASH)) + result = new Haval(); + else if (name.equalsIgnoreCase(Registry.MD5_HASH)) + result = new MD5(); + else if (name.equalsIgnoreCase(Registry.MD4_HASH)) + result = new MD4(); + else if (name.equalsIgnoreCase(Registry.MD2_HASH)) + result = new MD2(); + else if (name.equalsIgnoreCase(Registry.HAVAL_HASH)) + result = new Haval(); + + if (result != null && ! result.selfTest()) + throw new InternalError(result.name()); + + return result; + } + + /** + * Returns a {@link Set} of names of hash algorithms supported by this + * Factory. + * + * @return a {@link Set} of hash names (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(Registry.WHIRLPOOL_HASH); + hs.add(Registry.RIPEMD128_HASH); + hs.add(Registry.RIPEMD160_HASH); + hs.add(Registry.SHA160_HASH); + hs.add(Registry.SHA256_HASH); + hs.add(Registry.SHA384_HASH); + hs.add(Registry.SHA512_HASH); + hs.add(Registry.TIGER_HASH); + hs.add(Registry.HAVAL_HASH); + hs.add(Registry.MD5_HASH); + hs.add(Registry.MD4_HASH); + hs.add(Registry.MD2_HASH); + + return Collections.unmodifiableSet(hs); + } +} diff --git a/libjava/classpath/gnu/java/security/hash/Haval.java b/libjava/classpath/gnu/java/security/hash/Haval.java new file mode 100644 index 000000000..15c303934 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/Haval.java @@ -0,0 +1,807 @@ +/* Haval.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + * The HAVAL message-digest algorithm is a variable output length, with + * variable number of rounds. By default, this implementation allows HAVAL + * to be used as a drop-in replacement for MD5. + *

+ * References: + *

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

+ * A hash (or message digest) algorithm produces its output by iterating a basic + * compression function on blocks of data. + */ +public interface IMessageDigest + extends Cloneable +{ + /** + * Returns the canonical name of this algorithm. + * + * @return the canonical name of this instance. + */ + String name(); + + /** + * Returns the output length in bytes of this message digest algorithm. + * + * @return the output length in bytes of this message digest algorithm. + */ + int hashSize(); + + /** + * Returns the algorithm's (inner) block size in bytes. + * + * @return the algorithm's inner block size in bytes. + */ + int blockSize(); + + /** + * Continues a message digest operation using the input byte. + * + * @param b the input byte to digest. + */ + void update(byte b); + + /** + * Continues a message digest operation, by filling the buffer, processing + * data in the algorithm's HASH_SIZE-bit block(s), updating the context and + * count, and buffering the remaining bytes in buffer for the next operation. + * + * @param in the input block. + */ + void update(byte[] in); + + /** + * Continues a message digest operation, by filling the buffer, processing + * data in the algorithm's HASH_SIZE-bit block(s), updating the context and + * count, and buffering the remaining bytes in buffer for the next operation. + * + * @param in the input block. + * @param offset start of meaningful bytes in input block. + * @param length number of bytes, in input block, to consider. + */ + void update(byte[] in, int offset, int length); + + /** + * Completes the message digest by performing final operations such as padding + * and resetting the instance. + * + * @return the array of bytes representing the hash value. + */ + byte[] digest(); + + /** + * Resets the current context of this instance clearing any eventually cached + * intermediary values. + */ + void reset(); + + /** + * A basic test. Ensures that the digest of a pre-determined message is equal + * to a known pre-computed value. + * + * @return true if the implementation passes a basic self-test. + * Returns false otherwise. + */ + boolean selfTest(); + + /** + * Returns a clone copy of this instance. + * + * @return a clone copy of this instance. + */ + Object clone(); +} diff --git a/libjava/classpath/gnu/java/security/hash/MD2.java b/libjava/classpath/gnu/java/security/hash/MD2.java new file mode 100644 index 000000000..d78af93fa --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/MD2.java @@ -0,0 +1,256 @@ +/* MD2.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + * An implementation of the MD2 message digest algorithm. + *

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

+ * References: + *

    + *
  1. The MD2 + * Message-Digest Algorithm.
    + * B. Kaliski.
  2. + *
  3. The RFC ERRATA PAGE + * under section RFC 1319.
  4. + *
+ */ +public class MD2 + extends BaseHash +{ + /** An MD2 message digest is always 128-bits long, or 16 bytes. */ + private static final int DIGEST_LENGTH = 16; + + /** The MD2 algorithm operates on 128-bit blocks, or 16 bytes. */ + private static final int BLOCK_LENGTH = 16; + + /** 256 byte "random" permutation of the digits of pi. */ + private static final byte[] PI = { + 41, 46, 67, -55, -94, -40, 124, 1, + 61, 54, 84, -95, -20, -16, 6, 19, + 98, -89, 5, -13, -64, -57, 115, -116, + -104, -109, 43, -39, -68, 76, -126, -54, + 30, -101, 87, 60, -3, -44, -32, 22, + 103, 66, 111, 24, -118, 23, -27, 18, + -66, 78, -60, -42, -38, -98, -34, 73, + -96, -5, -11, -114, -69, 47, -18, 122, + -87, 104, 121, -111, 21, -78, 7, 63, + -108, -62, 16, -119, 11, 34, 95, 33, + -128, 127, 93, -102, 90, -112, 50, 39, + 53, 62, -52, -25, -65, -9, -105, 3, + -1, 25, 48, -77, 72, -91, -75, -47, + -41, 94, -110, 42, -84, 86, -86, -58, + 79, -72, 56, -46, -106, -92, 125, -74, + 118, -4, 107, -30, -100, 116, 4, -15, + 69, -99, 112, 89, 100, 113, -121, 32, + -122, 91, -49, 101, -26, 45, -88, 2, + 27, 96, 37, -83, -82, -80, -71, -10, + 28, 70, 97, 105, 52, 64, 126, 15, + 85, 71, -93, 35, -35, 81, -81, 58, + -61, 92, -7, -50, -70, -59, -22, 38, + 44, 83, 13, 110, -123, 40, -124, 9, + -45, -33, -51, -12, 65, -127, 77, 82, + 106, -36, 55, -56, 108, -63, -85, -6, + 36, -31, 123, 8, 12, -67, -79, 74, + 120, -120, -107, -117, -29, 99, -24, 109, + -23, -53, -43, -2, 59, 0, 29, 57, + -14, -17, -73, 14, 102, 88, -48, -28, + -90, 119, 114, -8, -21, 117, 75, 10, + 49, 68, 80, -76, -113, -19, 31, 26, + -37, -103, -115, 51, - 97, 17, -125, 20 }; + + /** The output of this message digest when no data has been input. */ + private static final String DIGEST0 = "8350E5A3E24C153DF2275C9F80692773"; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** The checksum computed so far. */ + private byte[] checksum; + + /** + * Work array needed by encrypt method. First BLOCK_LENGTH bytes + * are also used to store the running digest. + */ + private byte[] work; + + /** Creates a new MD2 digest ready for use. */ + public MD2() + { + super(Registry.MD2_HASH, DIGEST_LENGTH, BLOCK_LENGTH); + } + + /** + * Private constructor used for cloning. + * + * @param md2 the instance to clone. + */ + private MD2(MD2 md2) + { + this(); + + // superclass field + this.count = md2.count; + this.buffer = (byte[]) md2.buffer.clone(); + // private field + this.checksum = (byte[]) md2.checksum.clone(); + this.work = (byte[]) md2.work.clone(); + } + + public Object clone() + { + return new MD2(this); + } + + protected byte[] getResult() + { + byte[] result = new byte[DIGEST_LENGTH]; + // Encrypt checksum as last block. + encryptBlock(checksum, 0); + for (int i = 0; i < BLOCK_LENGTH; i++) + result[i] = work[i]; + + return result; + } + + protected void resetContext() + { + checksum = new byte[BLOCK_LENGTH]; + work = new byte[BLOCK_LENGTH * 3]; + } + + public boolean selfTest() + { + if (valid == null) + { + String d = Util.toString(new MD2().digest()); + valid = Boolean.valueOf(DIGEST0.equals(d)); + } + return valid.booleanValue(); + } + + /** + * Generates an array of padding bytes. The padding is defined as + * i bytes of value i, where i is the + * number of bytes to fill the last block of the message to + * BLOCK_LENGTH bytes (or BLOCK_LENGTH bytes when + * the last block was completely full). + * + * @return the bytes to pad the remaining bytes in the buffer before + * completing a hash operation. + */ + protected byte[] padBuffer() + { + int length = BLOCK_LENGTH - (int) (count % BLOCK_LENGTH); + if (length == 0) + length = BLOCK_LENGTH; + + byte[] pad = new byte[length]; + for (int i = 0; i < length; i++) + pad[i] = (byte) length; + + return pad; + } + + /** + * Adds BLOCK_LENGTH bytes to the running digest. + * + * @param in the byte array to take the BLOCK_LENGTH bytes from. + * @param off the offset to start from in the given byte array. + */ + protected void transform(byte[] in, int off) + { + updateCheckSumAndEncryptBlock(in, off); + } + + /** + * Adds a new block (BLOCK_LENGTH bytes) to the running digest + * from the given byte array starting from the given offset. + */ + private void encryptBlock(byte[] in, int off) + { + for (int i = 0; i < BLOCK_LENGTH; i++) + { + byte b = in[off + i]; + work[BLOCK_LENGTH + i] = b; + work[BLOCK_LENGTH * 2 + i] = (byte)(work[i] ^ b); + } + byte t = 0; + for (int i = 0; i < 18; i++) + { + for (int j = 0; j < 3 * BLOCK_LENGTH; j++) + { + t = (byte)(work[j] ^ PI[t & 0xFF]); + work[j] = t; + } + t = (byte)(t + i); + } + } + + /** + * Optimized method that combines a checksum update and encrypt of a block. + */ + private void updateCheckSumAndEncryptBlock(byte[] in, int off) + { + byte l = checksum[BLOCK_LENGTH - 1]; + for (int i = 0; i < BLOCK_LENGTH; i++) + { + byte b = in[off + i]; + work[BLOCK_LENGTH + i] = b; + work[BLOCK_LENGTH * 2 + i] = (byte)(work[i] ^ b); + l = (byte)(checksum[i] ^ PI[(b ^ l) & 0xFF]); + checksum[i] = l; + } + byte t = 0; + for (int i = 0; i < 18; i++) + { + for (int j = 0; j < 3 * BLOCK_LENGTH; j++) + { + t = (byte)(work[j] ^ PI[t & 0xFF]); + work[j] = t; + } + t = (byte)(t + i); + } + } +} diff --git a/libjava/classpath/gnu/java/security/hash/MD4.java b/libjava/classpath/gnu/java/security/hash/MD4.java new file mode 100644 index 000000000..e6ac11bc8 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/MD4.java @@ -0,0 +1,337 @@ +/* MD4.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + * An implementation of Ron Rivest's MD4 message digest algorithm. + *

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

+ * References: + *

    + *
  1. The MD4 + * Message-Digest Algorithm.
    + * R. Rivest.
  2. + *
+ * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class MD4 + extends BaseHash +{ + /** An MD4 message digest is always 128-bits long, or 16 bytes. */ + private static final int DIGEST_LENGTH = 16; + + /** The MD4 algorithm operates on 512-bit blocks, or 64 bytes. */ + private static final int BLOCK_LENGTH = 64; + + private static final int A = 0x67452301; + + private static final int B = 0xefcdab89; + + private static final int C = 0x98badcfe; + + private static final int D = 0x10325476; + + /** The output of this message digest when no data has been input. */ + private static final String DIGEST0 = "31D6CFE0D16AE931B73C59D7E0C089C0"; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + private int a, b, c, d; + + /** + * Public constructor. Initializes the chaining variables, sets the byte + * count to 0, and creates a new block of 512 bits. + */ + public MD4() + { + super(Registry.MD4_HASH, DIGEST_LENGTH, BLOCK_LENGTH); + } + + /** + * Trivial private constructor for cloning purposes. + * + * @param that the instance to clone. + */ + private MD4(MD4 that) + { + this(); + + this.a = that.a; + this.b = that.b; + this.c = that.c; + this.d = that.d; + this.count = that.count; + this.buffer = (byte[]) that.buffer.clone(); + } + + public Object clone() + { + return new MD4(this); + } + + protected byte[] getResult() + { + return new byte[] { + (byte) a, (byte)(a >>> 8), (byte)(a >>> 16), (byte)(a >>> 24), + (byte) b, (byte)(b >>> 8), (byte)(b >>> 16), (byte)(b >>> 24), + (byte) c, (byte)(c >>> 8), (byte)(c >>> 16), (byte)(c >>> 24), + (byte) d, (byte)(d >>> 8), (byte)(d >>> 16), (byte)(d >>> 24) }; + } + + protected void resetContext() + { + a = A; + b = B; + c = C; + d = D; + } + + public boolean selfTest() + { + if (valid == null) + { + String d = Util.toString(new MD4().digest()); + valid = Boolean.valueOf(DIGEST0.equals(d)); + } + return valid.booleanValue(); + } + + protected byte[] padBuffer() + { + int n = (int)(count % BLOCK_LENGTH); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] pad = new byte[padding + 8]; + pad[0] = (byte) 0x80; + long bits = count << 3; + pad[padding++] = (byte) bits; + pad[padding++] = (byte)(bits >>> 8); + pad[padding++] = (byte)(bits >>> 16); + pad[padding++] = (byte)(bits >>> 24); + pad[padding++] = (byte)(bits >>> 32); + pad[padding++] = (byte)(bits >>> 40); + pad[padding++] = (byte)(bits >>> 48); + pad[padding ] = (byte)(bits >>> 56); + return pad; + } + + protected void transform(byte[] in, int i) + { + int X0 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X1 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X2 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X3 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X4 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X5 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X6 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X7 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X8 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X9 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X10 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X11 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X12 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X13 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X14 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i++] << 24; + int X15 = (in[i++] & 0xFF) + | (in[i++] & 0xFF) << 8 + | (in[i++] & 0xFF) << 16 + | in[i] << 24; + int aa, bb, cc, dd; + aa = a; + bb = b; + cc = c; + dd = d; + + aa += ((bb & cc) | ((~bb) & dd)) + X0; + aa = aa << 3 | aa >>> -3; + dd += ((aa & bb) | ((~aa) & cc)) + X1; + dd = dd << 7 | dd >>> -7; + cc += ((dd & aa) | ((~dd) & bb)) + X2; + cc = cc << 11 | cc >>> -11; + bb += ((cc & dd) | ((~cc) & aa)) + X3; + bb = bb << 19 | bb >>> -19; + aa += ((bb & cc) | ((~bb) & dd)) + X4; + aa = aa << 3 | aa >>> -3; + dd += ((aa & bb) | ((~aa) & cc)) + X5; + dd = dd << 7 | dd >>> -7; + cc += ((dd & aa) | ((~dd) & bb)) + X6; + cc = cc << 11 | cc >>> -11; + bb += ((cc & dd) | ((~cc) & aa)) + X7; + bb = bb << 19 | bb >>> -19; + aa += ((bb & cc) | ((~bb) & dd)) + X8; + aa = aa << 3 | aa >>> -3; + dd += ((aa & bb) | ((~aa) & cc)) + X9; + dd = dd << 7 | dd >>> -7; + cc += ((dd & aa) | ((~dd) & bb)) + X10; + cc = cc << 11 | cc >>> -11; + bb += ((cc & dd) | ((~cc) & aa)) + X11; + bb = bb << 19 | bb >>> -19; + aa += ((bb & cc) | ((~bb) & dd)) + X12; + aa = aa << 3 | aa >>> -3; + dd += ((aa & bb) | ((~aa) & cc)) + X13; + dd = dd << 7 | dd >>> -7; + cc += ((dd & aa) | ((~dd) & bb)) + X14; + cc = cc << 11 | cc >>> -11; + bb += ((cc & dd) | ((~cc) & aa)) + X15; + bb = bb << 19 | bb >>> -19; + + aa += ((bb & (cc | dd)) | (cc & dd)) + X0 + 0x5a827999; + aa = aa << 3 | aa >>> -3; + dd += ((aa & (bb | cc)) | (bb & cc)) + X4 + 0x5a827999; + dd = dd << 5 | dd >>> -5; + cc += ((dd & (aa | bb)) | (aa & bb)) + X8 + 0x5a827999; + cc = cc << 9 | cc >>> -9; + bb += ((cc & (dd | aa)) | (dd & aa)) + X12 + 0x5a827999; + bb = bb << 13 | bb >>> -13; + aa += ((bb & (cc | dd)) | (cc & dd)) + X1 + 0x5a827999; + aa = aa << 3 | aa >>> -3; + dd += ((aa & (bb | cc)) | (bb & cc)) + X5 + 0x5a827999; + dd = dd << 5 | dd >>> -5; + cc += ((dd & (aa | bb)) | (aa & bb)) + X9 + 0x5a827999; + cc = cc << 9 | cc >>> -9; + bb += ((cc & (dd | aa)) | (dd & aa)) + X13 + 0x5a827999; + bb = bb << 13 | bb >>> -13; + aa += ((bb & (cc | dd)) | (cc & dd)) + X2 + 0x5a827999; + aa = aa << 3 | aa >>> -3; + dd += ((aa & (bb | cc)) | (bb & cc)) + X6 + 0x5a827999; + dd = dd << 5 | dd >>> -5; + cc += ((dd & (aa | bb)) | (aa & bb)) + X10 + 0x5a827999; + cc = cc << 9 | cc >>> -9; + bb += ((cc & (dd | aa)) | (dd & aa)) + X14 + 0x5a827999; + bb = bb << 13 | bb >>> -13; + aa += ((bb & (cc | dd)) | (cc & dd)) + X3 + 0x5a827999; + aa = aa << 3 | aa >>> -3; + dd += ((aa & (bb | cc)) | (bb & cc)) + X7 + 0x5a827999; + dd = dd << 5 | dd >>> -5; + cc += ((dd & (aa | bb)) | (aa & bb)) + X11 + 0x5a827999; + cc = cc << 9 | cc >>> -9; + bb += ((cc & (dd | aa)) | (dd & aa)) + X15 + 0x5a827999; + bb = bb << 13 | bb >>> -13; + + aa += (bb ^ cc ^ dd) + X0 + 0x6ed9eba1; + aa = aa << 3 | aa >>> -3; + dd += (aa ^ bb ^ cc) + X8 + 0x6ed9eba1; + dd = dd << 9 | dd >>> -9; + cc += (dd ^ aa ^ bb) + X4 + 0x6ed9eba1; + cc = cc << 11 | cc >>> -11; + bb += (cc ^ dd ^ aa) + X12 + 0x6ed9eba1; + bb = bb << 15 | bb >>> -15; + aa += (bb ^ cc ^ dd) + X2 + 0x6ed9eba1; + aa = aa << 3 | aa >>> -3; + dd += (aa ^ bb ^ cc) + X10 + 0x6ed9eba1; + dd = dd << 9 | dd >>> -9; + cc += (dd ^ aa ^ bb) + X6 + 0x6ed9eba1; + cc = cc << 11 | cc >>> -11; + bb += (cc ^ dd ^ aa) + X14 + 0x6ed9eba1; + bb = bb << 15 | bb >>> -15; + aa += (bb ^ cc ^ dd) + X1 + 0x6ed9eba1; + aa = aa << 3 | aa >>> -3; + dd += (aa ^ bb ^ cc) + X9 + 0x6ed9eba1; + dd = dd << 9 | dd >>> -9; + cc += (dd ^ aa ^ bb) + X5 + 0x6ed9eba1; + cc = cc << 11 | cc >>> -11; + bb += (cc ^ dd ^ aa) + X13 + 0x6ed9eba1; + bb = bb << 15 | bb >>> -15; + aa += (bb ^ cc ^ dd) + X3 + 0x6ed9eba1; + aa = aa << 3 | aa >>> -3; + dd += (aa ^ bb ^ cc) + X11 + 0x6ed9eba1; + dd = dd << 9 | dd >>> -9; + cc += (dd ^ aa ^ bb) + X7 + 0x6ed9eba1; + cc = cc << 11 | cc >>> -11; + bb += (cc ^ dd ^ aa) + X15 + 0x6ed9eba1; + bb = bb << 15 | bb >>> -15; + + a += aa; + b += bb; + c += cc; + d += dd; + } +} diff --git a/libjava/classpath/gnu/java/security/hash/MD5.java b/libjava/classpath/gnu/java/security/hash/MD5.java new file mode 100644 index 000000000..dfffd3c80 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/MD5.java @@ -0,0 +1,371 @@ +/* MD5.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + * The MD5 message-digest algorithm takes as input a message of arbitrary + * length and produces as output a 128-bit "fingerprint" or "message digest" of + * the input. It is conjectured that it is computationally infeasible to + * produce two messages having the same message digest, or to produce any + * message having a given prespecified target message digest. + *

+ * References: + *

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

+ * References: + *

    + *
  1. + * RIPEMD160: A Strengthened Version of RIPEMD.
    + * Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
  2. + *
+ */ +public class RipeMD128 + extends BaseHash +{ + private static final int BLOCK_SIZE = 64; // inner block size in bytes + + private static final String DIGEST0 = "CDF26213A150DC3ECB610F18F6B38B46"; + + /** Constants for the transform method. */ + // selection of message word + private static final int[] R = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2 }; + + private static final int[] Rp = { + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14 }; + + // amount for rotate left (rol) + private static final int[] S = { + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12 }; + + private static final int[] Sp = { + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8 }; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** 128-bit h0, h1, h2, h3 (interim result) */ + private int h0, h1, h2, h3; + + /** 512 bits work buffer = 16 x 32-bit words */ + private int[] X = new int[16]; + + /** Trivial 0-arguments constructor. */ + public RipeMD128() + { + super(Registry.RIPEMD128_HASH, 16, BLOCK_SIZE); + } + + /** + * Private constructor for cloning purposes. + * + * @param md the instance to clone. + */ + private RipeMD128(RipeMD128 md) + { + this(); + + this.h0 = md.h0; + this.h1 = md.h1; + this.h2 = md.h2; + this.h3 = md.h3; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + public Object clone() + { + return new RipeMD128(this); + } + + protected void transform(byte[] in, int offset) + { + int A, B, C, D, Ap, Bp, Cp, Dp, T, s, i; + // encode 64 bytes from input block into an array of 16 unsigned integers. + for (i = 0; i < 16; i++) + X[i] = (in[offset++] & 0xFF) + | (in[offset++] & 0xFF) << 8 + | (in[offset++] & 0xFF) << 16 + | in[offset++] << 24; + A = Ap = h0; + B = Bp = h1; + C = Cp = h2; + D = Dp = h3; + for (i = 0; i < 16; i++) // rounds 0...15 + { + s = S[i]; + T = A + (B ^ C ^ D) + X[i]; + A = D; + D = C; + C = B; + B = T << s | T >>> (32 - s); + + s = Sp[i]; + T = Ap + ((Bp & Dp) | (Cp & ~Dp)) + X[Rp[i]] + 0x50A28BE6; + Ap = Dp; + Dp = Cp; + Cp = Bp; + Bp = T << s | T >>> (32 - s); + } + for (; i < 32; i++) // rounds 16...31 + { + s = S[i]; + T = A + ((B & C) | (~B & D)) + X[R[i]] + 0x5A827999; + A = D; + D = C; + C = B; + B = T << s | T >>> (32 - s); + + s = Sp[i]; + T = Ap + ((Bp | ~Cp) ^ Dp) + X[Rp[i]] + 0x5C4DD124; + Ap = Dp; + Dp = Cp; + Cp = Bp; + Bp = T << s | T >>> (32 - s); + } + for (; i < 48; i++) // rounds 32...47 + { + s = S[i]; + T = A + ((B | ~C) ^ D) + X[R[i]] + 0x6ED9EBA1; + A = D; + D = C; + C = B; + B = T << s | T >>> (32 - s); + + s = Sp[i]; + T = Ap + ((Bp & Cp) | (~Bp & Dp)) + X[Rp[i]] + 0x6D703EF3; + Ap = Dp; + Dp = Cp; + Cp = Bp; + Bp = T << s | T >>> (32 - s); + } + for (; i < 64; i++) // rounds 48...63 + { + s = S[i]; + T = A + ((B & D) | (C & ~D)) + X[R[i]] + 0x8F1BBCDC; + A = D; + D = C; + C = B; + B = T << s | T >>> (32 - s); + + s = Sp[i]; + T = Ap + (Bp ^ Cp ^ Dp) + X[Rp[i]]; + Ap = Dp; + Dp = Cp; + Cp = Bp; + Bp = T << s | T >>> (32 - s); + } + T = h1 + C + Dp; + h1 = h2 + D + Ap; + h2 = h3 + A + Bp; + h3 = h0 + B + Cp; + h0 = T; + } + + protected byte[] padBuffer() + { + int n = (int)(count % BLOCK_SIZE); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] result = new byte[padding + 8]; + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + // save number of bits, casting the long to an array of 8 bytes + long bits = count << 3; + result[padding++] = (byte) bits; + result[padding++] = (byte)(bits >>> 8); + result[padding++] = (byte)(bits >>> 16); + result[padding++] = (byte)(bits >>> 24); + result[padding++] = (byte)(bits >>> 32); + result[padding++] = (byte)(bits >>> 40); + result[padding++] = (byte)(bits >>> 48); + result[padding ] = (byte)(bits >>> 56); + return result; + } + + protected byte[] getResult() + { + return new byte[] { + (byte) h0, (byte)(h0 >>> 8), (byte)(h0 >>> 16), (byte)(h0 >>> 24), + (byte) h1, (byte)(h1 >>> 8), (byte)(h1 >>> 16), (byte)(h1 >>> 24), + (byte) h2, (byte)(h2 >>> 8), (byte)(h2 >>> 16), (byte)(h2 >>> 24), + (byte) h3, (byte)(h3 >>> 8), (byte)(h3 >>> 16), (byte)(h3 >>> 24) + }; + } + + protected void resetContext() + { + // magic RIPEMD128 initialisation constants + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + } + + public boolean selfTest() + { + if (valid == null) + { + String d = Util.toString(new RipeMD128().digest()); + valid = Boolean.valueOf(DIGEST0.equals(d)); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/java/security/hash/RipeMD160.java b/libjava/classpath/gnu/java/security/hash/RipeMD160.java new file mode 100644 index 000000000..795f5a4b0 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/RipeMD160.java @@ -0,0 +1,291 @@ +/* RipeMD160.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + * RIPEMD-160 is a 160-bit message digest. + *

+ * References: + *

    + *
  1. + * RIPEMD160: A Strengthened Version of RIPEMD.
    + * Hans Dobbertin, Antoon Bosselaers and Bart Preneel.
  2. + *
+ */ +public class RipeMD160 + extends BaseHash +{ + private static final int BLOCK_SIZE = 64; // inner block size in bytes + + private static final String DIGEST0 = "9C1185A5C5E9FC54612808977EE8F548B2258D31"; + + // selection of message word + private static final int[] R = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8, + 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12, + 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2, + 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 }; + + private static final int[] Rp = { + 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12, + 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2, + 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13, + 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14, + 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 }; + + // amount for rotate left (rol) + private static final int[] S = { + 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8, + 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12, + 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5, + 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12, + 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 }; + + private static final int[] Sp = { + 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6, + 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11, + 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5, + 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8, + 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 }; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** 160-bit h0, h1, h2, h3, h4 (interim result) */ + private int h0, h1, h2, h3, h4; + + /** 512 bits work buffer = 16 x 32-bit words */ + private int[] X = new int[16]; + + /** Trivial 0-arguments constructor. */ + public RipeMD160() + { + super(Registry.RIPEMD160_HASH, 20, BLOCK_SIZE); + } + + /** + * Private constructor for cloning purposes. + * + * @param md the instance to clone. + */ + private RipeMD160(RipeMD160 md) + { + this(); + + this.h0 = md.h0; + this.h1 = md.h1; + this.h2 = md.h2; + this.h3 = md.h3; + this.h4 = md.h4; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + public Object clone() + { + return (new RipeMD160(this)); + } + + protected void transform(byte[] in, int offset) + { + int A, B, C, D, E, Ap, Bp, Cp, Dp, Ep, T, s, i; + // encode 64 bytes from input block into an array of 16 unsigned integers + for (i = 0; i < 16; i++) + X[i] = (in[offset++] & 0xFF) + | (in[offset++] & 0xFF) << 8 + | (in[offset++] & 0xFF) << 16 + | in[offset++] << 24; + A = Ap = h0; + B = Bp = h1; + C = Cp = h2; + D = Dp = h3; + E = Ep = h4; + for (i = 0; i < 16; i++) // rounds 0...15 + { + s = S[i]; + T = A + (B ^ C ^ D) + X[i]; + A = E; + E = D; + D = C << 10 | C >>> 22; + C = B; + B = (T << s | T >>> (32 - s)) + A; + + s = Sp[i]; + T = Ap + (Bp ^ (Cp | ~Dp)) + X[Rp[i]] + 0x50A28BE6; + Ap = Ep; + Ep = Dp; + Dp = Cp << 10 | Cp >>> 22; + Cp = Bp; + Bp = (T << s | T >>> (32 - s)) + Ap; + } + for (; i < 32; i++) // rounds 16...31 + { + s = S[i]; + T = A + ((B & C) | (~B & D)) + X[R[i]] + 0x5A827999; + A = E; + E = D; + D = C << 10 | C >>> 22; + C = B; + B = (T << s | T >>> (32 - s)) + A; + + s = Sp[i]; + T = Ap + ((Bp & Dp) | (Cp & ~Dp)) + X[Rp[i]] + 0x5C4DD124; + Ap = Ep; + Ep = Dp; + Dp = Cp << 10 | Cp >>> 22; + Cp = Bp; + Bp = (T << s | T >>> (32 - s)) + Ap; + } + for (; i < 48; i++) // rounds 32...47 + { + s = S[i]; + T = A + ((B | ~C) ^ D) + X[R[i]] + 0x6ED9EBA1; + A = E; + E = D; + D = C << 10 | C >>> 22; + C = B; + B = (T << s | T >>> (32 - s)) + A; + + s = Sp[i]; + T = Ap + ((Bp | ~Cp) ^ Dp) + X[Rp[i]] + 0x6D703EF3; + Ap = Ep; + Ep = Dp; + Dp = Cp << 10 | Cp >>> 22; + Cp = Bp; + Bp = (T << s | T >>> (32 - s)) + Ap; + } + for (; i < 64; i++) // rounds 48...63 + { + s = S[i]; + T = A + ((B & D) | (C & ~D)) + X[R[i]] + 0x8F1BBCDC; + A = E; + E = D; + D = C << 10 | C >>> 22; + C = B; + B = (T << s | T >>> (32 - s)) + A; + + s = Sp[i]; + T = Ap + ((Bp & Cp) | (~Bp & Dp)) + X[Rp[i]] + 0x7A6D76E9; + Ap = Ep; + Ep = Dp; + Dp = Cp << 10 | Cp >>> 22; + Cp = Bp; + Bp = (T << s | T >>> (32 - s)) + Ap; + } + for (; i < 80; i++) // rounds 64...79 + { + s = S[i]; + T = A + (B ^ (C | ~D)) + X[R[i]] + 0xA953FD4E; + A = E; + E = D; + D = C << 10 | C >>> 22; + C = B; + B = (T << s | T >>> (32 - s)) + A; + + s = Sp[i]; + T = Ap + (Bp ^ Cp ^ Dp) + X[Rp[i]]; + Ap = Ep; + Ep = Dp; + Dp = Cp << 10 | Cp >>> 22; + Cp = Bp; + Bp = (T << s | T >>> (32 - s)) + Ap; + } + T = h1 + C + Dp; + h1 = h2 + D + Ep; + h2 = h3 + E + Ap; + h3 = h4 + A + Bp; + h4 = h0 + B + Cp; + h0 = T; + } + + protected byte[] padBuffer() + { + int n = (int)(count % BLOCK_SIZE); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] result = new byte[padding + 8]; + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + // save number of bits, casting the long to an array of 8 bytes + long bits = count << 3; + result[padding++] = (byte) bits; + result[padding++] = (byte)(bits >>> 8); + result[padding++] = (byte)(bits >>> 16); + result[padding++] = (byte)(bits >>> 24); + result[padding++] = (byte)(bits >>> 32); + result[padding++] = (byte)(bits >>> 40); + result[padding++] = (byte)(bits >>> 48); + result[padding ] = (byte)(bits >>> 56); + return result; + } + + protected byte[] getResult() + { + return new byte[] { + (byte) h0, (byte)(h0 >>> 8), (byte)(h0 >>> 16), (byte)(h0 >>> 24), + (byte) h1, (byte)(h1 >>> 8), (byte)(h1 >>> 16), (byte)(h1 >>> 24), + (byte) h2, (byte)(h2 >>> 8), (byte)(h2 >>> 16), (byte)(h2 >>> 24), + (byte) h3, (byte)(h3 >>> 8), (byte)(h3 >>> 16), (byte)(h3 >>> 24), + (byte) h4, (byte)(h4 >>> 8), (byte)(h4 >>> 16), (byte)(h4 >>> 24) + }; + } + + protected void resetContext() + { + // magic RIPEMD160 initialisation constants + h0 = 0x67452301; + h1 = 0xEFCDAB89; + h2 = 0x98BADCFE; + h3 = 0x10325476; + h4 = 0xC3D2E1F0; + } + + public boolean selfTest() + { + if (valid == null) + { + String d = Util.toString(new RipeMD160().digest()); + valid = Boolean.valueOf(DIGEST0.equals(d)); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/java/security/hash/Sha160.java b/libjava/classpath/gnu/java/security/hash/Sha160.java new file mode 100644 index 000000000..88bf0e405 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/Sha160.java @@ -0,0 +1,241 @@ +/* Sha160.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + * The Secure Hash Algorithm (SHA-1) is required for use with the Digital + * Signature Algorithm (DSA) as specified in the Digital Signature Standard + * (DSS) and whenever a secure hash algorithm is required for federal + * applications. For a message of length less than 2^64 bits, the SHA-1 + * produces a 160-bit condensed representation of the message called a message + * digest. The message digest is used during generation of a signature for the + * message. The SHA-1 is also used to compute a message digest for the received + * version of the message during the process of verifying the signature. Any + * change to the message in transit will, with very high probability, result in + * a different message digest, and the signature will fail to verify. + *

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

+ * References: + *

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

+ * References: + *

    + *
  1. + * Descriptions of SHA-256, SHA-384, and SHA-512,
  2. + *
  3. http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf
  4. + *
+ */ +public class Sha256 + extends BaseHash +{ + private static final int[] k = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 + }; + + private static final int BLOCK_SIZE = 64; // inner block size in bytes + + private static final String DIGEST0 = + "BA7816BF8F01CFEA414140DE5DAE2223B00361A396177A9CB410FF61F20015AD"; + + private static final int[] w = new int[64]; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** 256-bit interim result. */ + private int h0, h1, h2, h3, h4, h5, h6, h7; + + /** Trivial 0-arguments constructor. */ + public Sha256() + { + super(Registry.SHA256_HASH, 32, BLOCK_SIZE); + } + + /** + * Private constructor for cloning purposes. + * + * @param md the instance to clone. + */ + private Sha256(Sha256 md) + { + this(); + + this.h0 = md.h0; + this.h1 = md.h1; + this.h2 = md.h2; + this.h3 = md.h3; + this.h4 = md.h4; + this.h5 = md.h5; + this.h6 = md.h6; + this.h7 = md.h7; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + public static final int[] G(int hh0, int hh1, int hh2, int hh3, int hh4, + int hh5, int hh6, int hh7, byte[] in, int offset) + { + return sha(hh0, hh1, hh2, hh3, hh4, hh5, hh6, hh7, in, offset); + } + + public Object clone() + { + return new Sha256(this); + } + + protected void transform(byte[] in, int offset) + { + int[] result = sha(h0, h1, h2, h3, h4, h5, h6, h7, in, offset); + h0 = result[0]; + h1 = result[1]; + h2 = result[2]; + h3 = result[3]; + h4 = result[4]; + h5 = result[5]; + h6 = result[6]; + h7 = result[7]; + } + + protected byte[] padBuffer() + { + int n = (int)(count % BLOCK_SIZE); + int padding = (n < 56) ? (56 - n) : (120 - n); + byte[] result = new byte[padding + 8]; + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + // save number of bits, casting the long to an array of 8 bytes + long bits = count << 3; + result[padding++] = (byte)(bits >>> 56); + result[padding++] = (byte)(bits >>> 48); + result[padding++] = (byte)(bits >>> 40); + result[padding++] = (byte)(bits >>> 32); + result[padding++] = (byte)(bits >>> 24); + result[padding++] = (byte)(bits >>> 16); + result[padding++] = (byte)(bits >>> 8); + result[padding ] = (byte) bits; + return result; + } + + protected byte[] getResult() + { + return new byte[] { + (byte)(h0 >>> 24), (byte)(h0 >>> 16), (byte)(h0 >>> 8), (byte) h0, + (byte)(h1 >>> 24), (byte)(h1 >>> 16), (byte)(h1 >>> 8), (byte) h1, + (byte)(h2 >>> 24), (byte)(h2 >>> 16), (byte)(h2 >>> 8), (byte) h2, + (byte)(h3 >>> 24), (byte)(h3 >>> 16), (byte)(h3 >>> 8), (byte) h3, + (byte)(h4 >>> 24), (byte)(h4 >>> 16), (byte)(h4 >>> 8), (byte) h4, + (byte)(h5 >>> 24), (byte)(h5 >>> 16), (byte)(h5 >>> 8), (byte) h5, + (byte)(h6 >>> 24), (byte)(h6 >>> 16), (byte)(h6 >>> 8), (byte) h6, + (byte)(h7 >>> 24), (byte)(h7 >>> 16), (byte)(h7 >>> 8), (byte) h7 }; + } + + protected void resetContext() + { + // magic SHA-256 initialisation constants + h0 = 0x6a09e667; + h1 = 0xbb67ae85; + h2 = 0x3c6ef372; + h3 = 0xa54ff53a; + h4 = 0x510e527f; + h5 = 0x9b05688c; + h6 = 0x1f83d9ab; + h7 = 0x5be0cd19; + } + + public boolean selfTest() + { + if (valid == null) + { + Sha256 md = new Sha256(); + md.update((byte) 0x61); // a + md.update((byte) 0x62); // b + md.update((byte) 0x63); // c + String result = Util.toString(md.digest()); + valid = Boolean.valueOf(DIGEST0.equals(result)); + } + return valid.booleanValue(); + } + + private static synchronized final int[] sha(int hh0, int hh1, int hh2, + int hh3, int hh4, int hh5, + int hh6, int hh7, byte[] in, + int offset) + { + int A = hh0; + int B = hh1; + int C = hh2; + int D = hh3; + int E = hh4; + int F = hh5; + int G = hh6; + int H = hh7; + int r, T, T2; + for (r = 0; r < 16; r++) + w[r] = (in[offset++] << 24 + | (in[offset++] & 0xFF) << 16 + | (in[offset++] & 0xFF) << 8 + | (in[offset++] & 0xFF)); + for (r = 16; r < 64; r++) + { + T = w[r - 2]; + T2 = w[r - 15]; + w[r] = ((((T >>> 17) | (T << 15)) ^ ((T >>> 19) | (T << 13)) ^ (T >>> 10)) + + w[r - 7] + + (((T2 >>> 7) | (T2 << 25)) + ^ ((T2 >>> 18) | (T2 << 14)) + ^ (T2 >>> 3)) + w[r - 16]); + } + for (r = 0; r < 64; r++) + { + T = (H + + (((E >>> 6) | (E << 26)) + ^ ((E >>> 11) | (E << 21)) + ^ ((E >>> 25) | (E << 7))) + + ((E & F) ^ (~E & G)) + k[r] + w[r]); + T2 = ((((A >>> 2) | (A << 30)) + ^ ((A >>> 13) | (A << 19)) + ^ ((A >>> 22) | (A << 10))) + ((A & B) ^ (A & C) ^ (B & C))); + H = G; + G = F; + F = E; + E = D + T; + D = C; + C = B; + B = A; + A = T + T2; + } + return new int[] { + hh0 + A, hh1 + B, hh2 + C, hh3 + D, + hh4 + E, hh5 + F, hh6 + G, hh7 + H }; + } +} diff --git a/libjava/classpath/gnu/java/security/hash/Sha384.java b/libjava/classpath/gnu/java/security/hash/Sha384.java new file mode 100644 index 000000000..5fea4f3b1 --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/Sha384.java @@ -0,0 +1,279 @@ +/* Sha384.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + * Implementation of SHA2-2 [SHA-384] per the IETF Draft Specification. + *

+ * References: + *

    + *
  1. + * Descriptions of SHA-256, SHA-384, and SHA-512,
  2. + *
  3. http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf
  4. + *
+ */ +public class Sha384 + extends BaseHash +{ + private static final long[] k = { + 0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL, + 0xe9b5dba58189dbbcL, 0x3956c25bf348b538L, 0x59f111f1b605d019L, + 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L, 0xd807aa98a3030242L, + 0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L, + 0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L, + 0xc19bf174cf692694L, 0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L, + 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L, 0x2de92c6f592b0275L, + 0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L, + 0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL, + 0xbf597fc7beef0ee4L, 0xc6e00bf33da88fc2L, 0xd5a79147930aa725L, + 0x06ca6351e003826fL, 0x142929670a0e6e70L, 0x27b70a8546d22ffcL, + 0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL, + 0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L, + 0x92722c851482353bL, 0xa2bfe8a14cf10364L, 0xa81a664bbc423001L, + 0xc24b8b70d0f89791L, 0xc76c51a30654be30L, 0xd192e819d6ef5218L, + 0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L, + 0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L, + 0x34b0bcb5e19b48a8L, 0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, + 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L, 0x748f82ee5defb2fcL, + 0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL, + 0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L, + 0xc67178f2e372532bL, 0xca273eceea26619cL, 0xd186b8c721c0c207L, + 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L, 0x06f067aa72176fbaL, + 0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL, + 0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, + 0x431d67c49c100d4cL, 0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, + 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L }; + + private static final int BLOCK_SIZE = 128; // inner block size in bytes + + private static final String DIGEST0 = + "CB00753F45A35E8BB5A03D699AC65007272C32AB0EDED1631A8B605A43FF5BED" + + "8086072BA1E7CC2358BAECA134C825A7"; + + private static final long[] w = new long[80]; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** 512-bit interim result. */ + private long h0, h1, h2, h3, h4, h5, h6, h7; + + /** Trivial 0-arguments constructor. */ + public Sha384() + { + super(Registry.SHA384_HASH, 48, BLOCK_SIZE); + } + + /** + * Private constructor for cloning purposes. + * + * @param md the instance to clone. + */ + private Sha384(Sha384 md) + { + this(); + + this.h0 = md.h0; + this.h1 = md.h1; + this.h2 = md.h2; + this.h3 = md.h3; + this.h4 = md.h4; + this.h5 = md.h5; + this.h6 = md.h6; + this.h7 = md.h7; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + public static final long[] G(long hh0, long hh1, long hh2, long hh3, + long hh4, long hh5, long hh6, long hh7, + byte[] in, int offset) + { + return sha(hh0, hh1, hh2, hh3, hh4, hh5, hh6, hh7, in, offset); + } + + public Object clone() + { + return new Sha384(this); + } + + protected void transform(byte[] in, int offset) + { + long[] result = sha(h0, h1, h2, h3, h4, h5, h6, h7, in, offset); + h0 = result[0]; + h1 = result[1]; + h2 = result[2]; + h3 = result[3]; + h4 = result[4]; + h5 = result[5]; + h6 = result[6]; + h7 = result[7]; + } + + protected byte[] padBuffer() + { + int n = (int)(count % BLOCK_SIZE); + int padding = (n < 112) ? (112 - n) : (240 - n); + byte[] result = new byte[padding + 16]; + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + // save number of bits, casting the long to an array of 8 bytes + // TODO: FIX Only ~35 bits of 128 bit counter usable this way + long bits = count << 3; + padding += 8; + result[padding++] = (byte)(bits >>> 56); + result[padding++] = (byte)(bits >>> 48); + result[padding++] = (byte)(bits >>> 40); + result[padding++] = (byte)(bits >>> 32); + result[padding++] = (byte)(bits >>> 24); + result[padding++] = (byte)(bits >>> 16); + result[padding++] = (byte)(bits >>> 8); + result[padding ] = (byte) bits; + return result; + } + + protected byte[] getResult() + { + return new byte[] { + (byte)(h0 >>> 56), (byte)(h0 >>> 48), (byte)(h0 >>> 40), (byte)(h0 >>> 32), + (byte)(h0 >>> 24), (byte)(h0 >>> 16), (byte)(h0 >>> 8), (byte) h0, + (byte)(h1 >>> 56), (byte)(h1 >>> 48), (byte)(h1 >>> 40), (byte)(h1 >>> 32), + (byte)(h1 >>> 24), (byte)(h1 >>> 16), (byte)(h1 >>> 8), (byte) h1, + (byte)(h2 >>> 56), (byte)(h2 >>> 48), (byte)(h2 >>> 40), (byte)(h2 >>> 32), + (byte)(h2 >>> 24), (byte)(h2 >>> 16), (byte)(h2 >>> 8), (byte) h2, + (byte)(h3 >>> 56), (byte)(h3 >>> 48), (byte)(h3 >>> 40), (byte)(h3 >>> 32), + (byte)(h3 >>> 24), (byte)(h3 >>> 16), (byte)(h3 >>> 8), (byte) h3, + (byte)(h4 >>> 56), (byte)(h4 >>> 48), (byte)(h4 >>> 40), (byte)(h4 >>> 32), + (byte)(h4 >>> 24), (byte)(h4 >>> 16), (byte)(h4 >>> 8), (byte) h4, + (byte)(h5 >>> 56), (byte)(h5 >>> 48), (byte)(h5 >>> 40), (byte)(h5 >>> 32), + (byte)(h5 >>> 24), (byte)(h5 >>> 16), (byte)(h5 >>> 8), (byte) h5 }; + } + + protected void resetContext() + { + // magic SHA-384 initialisation constants + h0 = 0xcbbb9d5dc1059ed8L; + h1 = 0x629a292a367cd507L; + h2 = 0x9159015a3070dd17L; + h3 = 0x152fecd8f70e5939L; + h4 = 0x67332667ffc00b31L; + h5 = 0x8eb44a8768581511L; + h6 = 0xdb0c2e0d64f98fa7L; + h7 = 0x47b5481dbefa4fa4L; + } + + public boolean selfTest() + { + if (valid == null) + { + Sha384 md = new Sha384(); + md.update((byte) 0x61); // a + md.update((byte) 0x62); // b + md.update((byte) 0x63); // c + String result = Util.toString(md.digest()); + valid = Boolean.valueOf(DIGEST0.equals(result)); + } + return valid.booleanValue(); + } + + private static synchronized final long[] sha(long hh0, long hh1, long hh2, + long hh3, long hh4, long hh5, + long hh6, long hh7, byte[] in, + int offset) + { + long A = hh0; + long B = hh1; + long C = hh2; + long D = hh3; + long E = hh4; + long F = hh5; + long G = hh6; + long H = hh7; + long T, T2; + int r; + for (r = 0; r < 16; r++) + w[r] = (long) in[offset++] << 56 + | ((long) in[offset++] & 0xFF) << 48 + | ((long) in[offset++] & 0xFF) << 40 + | ((long) in[offset++] & 0xFF) << 32 + | ((long) in[offset++] & 0xFF) << 24 + | ((long) in[offset++] & 0xFF) << 16 + | ((long) in[offset++] & 0xFF) << 8 + | ((long) in[offset++] & 0xFF); + for (r = 16; r < 80; r++) + { + T = w[r - 2]; + T2 = w[r - 15]; + w[r] = (((T >>> 19) | (T << 45)) ^ ((T >>> 61) | (T << 3)) ^ (T >>> 6)) + + w[r - 7] + + (((T2 >>> 1) | (T2 << 63)) + ^ ((T2 >>> 8) | (T2 << 56)) + ^ (T2 >>> 7)) + + w[r - 16]; + } + for (r = 0; r < 80; r++) + { + + T = H + + (((E >>> 14) | (E << 50)) + ^ ((E >>> 18) | (E << 46)) + ^ ((E >>> 41) | (E << 23))) + + ((E & F) ^ ((~E) & G)) + k[r] + w[r]; + // T IS INCORRECT SOMEHOW + T2 = (((A >>> 28) | (A << 36)) + ^ ((A >>> 34) | (A << 30)) + ^ ((A >>> 39) | (A << 25))) + + ((A & B) ^ (A & C) ^ (B & C)); + H = G; + G = F; + F = E; + E = D + T; + D = C; + C = B; + B = A; + A = T + T2; + } + return new long[] { + hh0 + A, hh1 + B, hh2 + C, hh3 + D, + hh4 + E, hh5 + F, hh6 + G, hh7 + H }; + } +} diff --git a/libjava/classpath/gnu/java/security/hash/Sha512.java b/libjava/classpath/gnu/java/security/hash/Sha512.java new file mode 100644 index 000000000..17c4323fa --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/Sha512.java @@ -0,0 +1,281 @@ +/* Sha512.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + * Implementation of SHA2-3 [SHA-512] per the IETF Draft Specification. + *

+ * References: + *

    + *
  1. + * Descriptions of SHA-256, SHA-384, and SHA-512,
  2. + *
  3. http://csrc.nist.gov/cryptval/shs/sha256-384-512.pdf
  4. + *
+ */ +public class Sha512 + extends BaseHash +{ + private static final long[] k = { + 0x428a2f98d728ae22L, 0x7137449123ef65cdL, 0xb5c0fbcfec4d3b2fL, + 0xe9b5dba58189dbbcL, 0x3956c25bf348b538L, 0x59f111f1b605d019L, + 0x923f82a4af194f9bL, 0xab1c5ed5da6d8118L, 0xd807aa98a3030242L, + 0x12835b0145706fbeL, 0x243185be4ee4b28cL, 0x550c7dc3d5ffb4e2L, + 0x72be5d74f27b896fL, 0x80deb1fe3b1696b1L, 0x9bdc06a725c71235L, + 0xc19bf174cf692694L, 0xe49b69c19ef14ad2L, 0xefbe4786384f25e3L, + 0x0fc19dc68b8cd5b5L, 0x240ca1cc77ac9c65L, 0x2de92c6f592b0275L, + 0x4a7484aa6ea6e483L, 0x5cb0a9dcbd41fbd4L, 0x76f988da831153b5L, + 0x983e5152ee66dfabL, 0xa831c66d2db43210L, 0xb00327c898fb213fL, + 0xbf597fc7beef0ee4L, 0xc6e00bf33da88fc2L, 0xd5a79147930aa725L, + 0x06ca6351e003826fL, 0x142929670a0e6e70L, 0x27b70a8546d22ffcL, + 0x2e1b21385c26c926L, 0x4d2c6dfc5ac42aedL, 0x53380d139d95b3dfL, + 0x650a73548baf63deL, 0x766a0abb3c77b2a8L, 0x81c2c92e47edaee6L, + 0x92722c851482353bL, 0xa2bfe8a14cf10364L, 0xa81a664bbc423001L, + 0xc24b8b70d0f89791L, 0xc76c51a30654be30L, 0xd192e819d6ef5218L, + 0xd69906245565a910L, 0xf40e35855771202aL, 0x106aa07032bbd1b8L, + 0x19a4c116b8d2d0c8L, 0x1e376c085141ab53L, 0x2748774cdf8eeb99L, + 0x34b0bcb5e19b48a8L, 0x391c0cb3c5c95a63L, 0x4ed8aa4ae3418acbL, + 0x5b9cca4f7763e373L, 0x682e6ff3d6b2b8a3L, 0x748f82ee5defb2fcL, + 0x78a5636f43172f60L, 0x84c87814a1f0ab72L, 0x8cc702081a6439ecL, + 0x90befffa23631e28L, 0xa4506cebde82bde9L, 0xbef9a3f7b2c67915L, + 0xc67178f2e372532bL, 0xca273eceea26619cL, 0xd186b8c721c0c207L, + 0xeada7dd6cde0eb1eL, 0xf57d4f7fee6ed178L, 0x06f067aa72176fbaL, + 0x0a637dc5a2c898a6L, 0x113f9804bef90daeL, 0x1b710b35131c471bL, + 0x28db77f523047d84L, 0x32caab7b40c72493L, 0x3c9ebe0a15c9bebcL, + 0x431d67c49c100d4cL, 0x4cc5d4becb3e42b6L, 0x597f299cfc657e2aL, + 0x5fcb6fab3ad6faecL, 0x6c44198c4a475817L }; + + private static final int BLOCK_SIZE = 128; // inner block size in bytes + + private static final String DIGEST0 = + "DDAF35A193617ABACC417349AE20413112E6FA4E89A97EA20A9EEEE64B55D39A" + + "2192992A274FC1A836BA3C23A3FEEBBD454D4423643CE80E2A9AC94FA54CA49F"; + + private static final long[] w = new long[80]; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** 512-bit interim result. */ + private long h0, h1, h2, h3, h4, h5, h6, h7; + + /** Trivial 0-arguments constructor. */ + public Sha512() + { + super(Registry.SHA512_HASH, 64, BLOCK_SIZE); + } + + /** + * Private constructor for cloning purposes. + * + * @param md the instance to clone. + */ + private Sha512(Sha512 md) + { + this(); + + this.h0 = md.h0; + this.h1 = md.h1; + this.h2 = md.h2; + this.h3 = md.h3; + this.h4 = md.h4; + this.h5 = md.h5; + this.h6 = md.h6; + this.h7 = md.h7; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + public static final long[] G(long hh0, long hh1, long hh2, long hh3, + long hh4, long hh5, long hh6, long hh7, + byte[] in, int offset) + { + return sha(hh0, hh1, hh2, hh3, hh4, hh5, hh6, hh7, in, offset); + } + + public Object clone() + { + return new Sha512(this); + } + + protected void transform(byte[] in, int offset) + { + long[] result = sha(h0, h1, h2, h3, h4, h5, h6, h7, in, offset); + h0 = result[0]; + h1 = result[1]; + h2 = result[2]; + h3 = result[3]; + h4 = result[4]; + h5 = result[5]; + h6 = result[6]; + h7 = result[7]; + } + + protected byte[] padBuffer() + { + int n = (int)(count % BLOCK_SIZE); + int padding = (n < 112) ? (112 - n) : (240 - n); + byte[] result = new byte[padding + 16]; + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + // save number of bits, casting the long to an array of 8 bytes + // TODO: FIX Only ~35 bits of 128 bit counter usable this way + long bits = count << 3; + padding += 8; + result[padding++] = (byte)(bits >>> 56); + result[padding++] = (byte)(bits >>> 48); + result[padding++] = (byte)(bits >>> 40); + result[padding++] = (byte)(bits >>> 32); + result[padding++] = (byte)(bits >>> 24); + result[padding++] = (byte)(bits >>> 16); + result[padding++] = (byte)(bits >>> 8); + result[padding ] = (byte) bits; + return result; + } + + protected byte[] getResult() + { + return new byte[] { + (byte)(h0 >>> 56), (byte)(h0 >>> 48), (byte)(h0 >>> 40), (byte)(h0 >>> 32), + (byte)(h0 >>> 24), (byte)(h0 >>> 16), (byte)(h0 >>> 8), (byte) h0, + (byte)(h1 >>> 56), (byte)(h1 >>> 48), (byte)(h1 >>> 40), (byte)(h1 >>> 32), + (byte)(h1 >>> 24), (byte)(h1 >>> 16), (byte)(h1 >>> 8), (byte) h1, + (byte)(h2 >>> 56), (byte)(h2 >>> 48), (byte)(h2 >>> 40), (byte)(h2 >>> 32), + (byte)(h2 >>> 24), (byte)(h2 >>> 16), (byte)(h2 >>> 8), (byte) h2, + (byte)(h3 >>> 56), (byte)(h3 >>> 48), (byte)(h3 >>> 40), (byte)(h3 >>> 32), + (byte)(h3 >>> 24), (byte)(h3 >>> 16), (byte)(h3 >>> 8), (byte) h3, + (byte)(h4 >>> 56), (byte)(h4 >>> 48), (byte)(h4 >>> 40), (byte)(h4 >>> 32), + (byte)(h4 >>> 24), (byte)(h4 >>> 16), (byte)(h4 >>> 8), (byte) h4, + (byte)(h5 >>> 56), (byte)(h5 >>> 48), (byte)(h5 >>> 40), (byte)(h5 >>> 32), + (byte)(h5 >>> 24), (byte)(h5 >>> 16), (byte)(h5 >>> 8), (byte) h5, + (byte)(h6 >>> 56), (byte)(h6 >>> 48), (byte)(h6 >>> 40), (byte)(h6 >>> 32), + (byte)(h6 >>> 24), (byte)(h6 >>> 16), (byte)(h6 >>> 8), (byte) h6, + (byte)(h7 >>> 56), (byte)(h7 >>> 48), (byte)(h7 >>> 40), (byte)(h7 >>> 32), + (byte)(h7 >>> 24), (byte)(h7 >>> 16), (byte)(h7 >>> 8), (byte) h7 }; + } + + protected void resetContext() + { + // magic SHA-512 initialisation constants + h0 = 0x6a09e667f3bcc908L; + h1 = 0xbb67ae8584caa73bL; + h2 = 0x3c6ef372fe94f82bL; + h3 = 0xa54ff53a5f1d36f1L; + h4 = 0x510e527fade682d1L; + h5 = 0x9b05688c2b3e6c1fL; + h6 = 0x1f83d9abfb41bd6bL; + h7 = 0x5be0cd19137e2179L; + } + + public boolean selfTest() + { + if (valid == null) + { + Sha512 md = new Sha512(); + md.update((byte) 0x61); // a + md.update((byte) 0x62); // b + md.update((byte) 0x63); // c + String result = Util.toString(md.digest()); + valid = Boolean.valueOf(DIGEST0.equals(result)); + } + return valid.booleanValue(); + } + + private static synchronized final long[] sha(long hh0, long hh1, long hh2, + long hh3, long hh4, long hh5, + long hh6, long hh7, byte[] in, + int offset) + { + long A = hh0; + long B = hh1; + long C = hh2; + long D = hh3; + long E = hh4; + long F = hh5; + long G = hh6; + long H = hh7; + long T, T2; + int r; + for (r = 0; r < 16; r++) + w[r] = (long) in[offset++] << 56 + | ((long) in[offset++] & 0xFF) << 48 + | ((long) in[offset++] & 0xFF) << 40 + | ((long) in[offset++] & 0xFF) << 32 + | ((long) in[offset++] & 0xFF) << 24 + | ((long) in[offset++] & 0xFF) << 16 + | ((long) in[offset++] & 0xFF) << 8 + | ((long) in[offset++] & 0xFF); + for (r = 16; r < 80; r++) + { + T = w[r - 2]; + T2 = w[r - 15]; + w[r] = (((T >>> 19) | (T << 45)) ^ ((T >>> 61) | (T << 3)) ^ (T >>> 6)) + + w[r - 7] + + (((T2 >>> 1) | (T2 << 63)) + ^ ((T2 >>> 8) | (T2 << 56)) + ^ (T2 >>> 7)) + + w[r - 16]; + } + for (r = 0; r < 80; r++) + { + T = H + + (((E >>> 14) | (E << 50)) + ^ ((E >>> 18) | (E << 46)) + ^ ((E >>> 41) | (E << 23))) + + ((E & F) ^ ((~E) & G)) + k[r] + w[r]; + T2 = (((A >>> 28) | (A << 36)) + ^ ((A >>> 34) | (A << 30)) + ^ ((A >>> 39) | (A << 25))) + + ((A & B) ^ (A & C) ^ (B & C)); + H = G; + G = F; + F = E; + E = D + T; + D = C; + C = B; + B = A; + A = T + T2; + } + return new long[] { + hh0 + A, hh1 + B, hh2 + C, hh3 + D, + hh4 + E, hh5 + F, hh6 + G, hh7 + H }; + } +} diff --git a/libjava/classpath/gnu/java/security/hash/Tiger.java b/libjava/classpath/gnu/java/security/hash/Tiger.java new file mode 100644 index 000000000..d2993db9f --- /dev/null +++ b/libjava/classpath/gnu/java/security/hash/Tiger.java @@ -0,0 +1,864 @@ +/* Tiger.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.hash; + +import gnu.java.security.Registry; +import gnu.java.security.util.Util; + +/** + * The Tiger message digest. Tiger was designed by Ross Anderson and Eli + * Biham, with the goal of producing a secure, fast hash function that + * performs especially well on next-generation 64-bit architectures, but + * is still efficient on 32- and 16-bit architectures. + *

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

+ * References: + *

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

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

+ * IMPORTANT: This implementation is not thread-safe. + *

+ * References: + *

    + *
  1. + * The WHIRLPOOL Hashing Function.
    + * Paulo S.L.M. Barreto and + * Vincent Rijmen.
  2. + *
+ */ +public final class Whirlpool + extends BaseHash +{ + private static final Logger log = Logger.getLogger(Whirlpool.class.getName()); + private static final int BLOCK_SIZE = 64; // inner block size in bytes + + /** The digest of the 0-bit long message. */ + private static final String DIGEST0 = + "19FA61D75522A4669B44E39C1D2E1726C530232130D407F89AFEE0964997F7A7" + + "3E83BE698B288FEBCF88E3E03C4F0757EA8964E59B63D93708B138CC42A66EB3"; + + /** Default number of rounds. */ + private static final int R = 10; + + /** Whirlpool S-box; p. 19. */ + private static final String S_box = // p. 19 [WHIRLPOOL] + "\u1823\uc6E8\u87B8\u014F\u36A6\ud2F5\u796F\u9152" + + "\u60Bc\u9B8E\uA30c\u7B35\u1dE0\ud7c2\u2E4B\uFE57" + + "\u1577\u37E5\u9FF0\u4AdA\u58c9\u290A\uB1A0\u6B85" + + "\uBd5d\u10F4\ucB3E\u0567\uE427\u418B\uA77d\u95d8" + + "\uFBEE\u7c66\udd17\u479E\ucA2d\uBF07\uAd5A\u8333" + + "\u6302\uAA71\uc819\u49d9\uF2E3\u5B88\u9A26\u32B0" + + "\uE90F\ud580\uBEcd\u3448\uFF7A\u905F\u2068\u1AAE" + + "\uB454\u9322\u64F1\u7312\u4008\uc3Ec\udBA1\u8d3d" + + "\u9700\ucF2B\u7682\ud61B\uB5AF\u6A50\u45F3\u30EF" + + "\u3F55\uA2EA\u65BA\u2Fc0\udE1c\uFd4d\u9275\u068A" + + "\uB2E6\u0E1F\u62d4\uA896\uF9c5\u2559\u8472\u394c" + + "\u5E78\u388c\ud1A5\uE261\uB321\u9c1E\u43c7\uFc04" + + "\u5199\u6d0d\uFAdF\u7E24\u3BAB\ucE11\u8F4E\uB7EB" + + "\u3c81\u94F7\uB913\u2cd3\uE76E\uc403\u5644\u7FA9" + + "\u2ABB\uc153\udc0B\u9d6c\u3174\uF646\uAc89\u14E1" + + "\u163A\u6909\u70B6\ud0Ed\ucc42\u98A4\u285c\uF886"; + + /** The 64-bit lookup tables; section 7.1 p. 13. */ + private static final long[] T0 = new long[256]; + private static final long[] T1 = new long[256]; + private static final long[] T2 = new long[256]; + private static final long[] T3 = new long[256]; + private static final long[] T4 = new long[256]; + private static final long[] T5 = new long[256]; + private static final long[] T6 = new long[256]; + private static final long[] T7 = new long[256]; + + /** The round constants. */ + private static final long[] rc = new long[R]; + + /** caches the result of the correctness test, once executed. */ + private static Boolean valid; + + /** The 512-bit context as 8 longs. */ + private long H0, H1, H2, H3, H4, H5, H6, H7; + + /** Work area for computing the round key schedule. */ + private long k00, k01, k02, k03, k04, k05, k06, k07; + private long Kr0, Kr1, Kr2, Kr3, Kr4, Kr5, Kr6, Kr7; + + /** work area for transforming the 512-bit buffer. */ + private long n0, n1, n2, n3, n4, n5, n6, n7; + private long nn0, nn1, nn2, nn3, nn4, nn5, nn6, nn7; + + /** work area for holding block cipher's intermediate values. */ + private long w0, w1, w2, w3, w4, w5, w6, w7; + + static + { + long time = System.currentTimeMillis(); + int ROOT = 0x11D; // para. 2.1 [WHIRLPOOL] + int i, r, j; + long s1, s2, s4, s5, s8, s9, t; + char c; + final byte[] S = new byte[256]; + for (i = 0; i < 256; i++) + { + c = S_box.charAt(i >>> 1); + + s1 = ((i & 1) == 0 ? c >>> 8 : c) & 0xFFL; + s2 = s1 << 1; + if (s2 > 0xFFL) + s2 ^= ROOT; + + s4 = s2 << 1; + if (s4 > 0xFFL) + s4 ^= ROOT; + + s5 = s4 ^ s1; + s8 = s4 << 1; + if (s8 > 0xFFL) + s8 ^= ROOT; + + s9 = s8 ^ s1; + + T0[i] = t = s1 << 56 | s1 << 48 | s4 << 40 | s1 << 32 + | s8 << 24 | s5 << 16 | s2 << 8 | s9; + T1[i] = t >>> 8 | t << 56; + T2[i] = t >>> 16 | t << 48; + T3[i] = t >>> 24 | t << 40; + T4[i] = t >>> 32 | t << 32; + T5[i] = t >>> 40 | t << 24; + T6[i] = t >>> 48 | t << 16; + T7[i] = t >>> 56 | t << 8; + } + for (r = 0, i = 0; r < R; ) + rc[r++] = (T0[i++] & 0xFF00000000000000L) + ^ (T1[i++] & 0x00FF000000000000L) + ^ (T2[i++] & 0x0000FF0000000000L) + ^ (T3[i++] & 0x000000FF00000000L) + ^ (T4[i++] & 0x00000000FF000000L) + ^ (T5[i++] & 0x0000000000FF0000L) + ^ (T6[i++] & 0x000000000000FF00L) + ^ (T7[i++] & 0x00000000000000FFL); + time = System.currentTimeMillis() - time; + if (Configuration.DEBUG) + { + log.fine("Static data"); + log.fine("T0[]:"); + CPStringBuilder sb; + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T0[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("T1[]:"); + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T1[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("T2[]:"); + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T2[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("T3[]:"); + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T3[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("\nT4[]:"); + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T4[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("T5[]:"); + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T5[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("T6[]:"); + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T5[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("T7[]:"); + for (i = 0; i < 64; i++) + { + sb = new CPStringBuilder(); + for (j = 0; j < 4; j++) + sb.append("0x").append(Util.toString(T5[i * 4 + j])).append(", "); + + log.fine(sb.toString()); + } + log.fine("rc[]:"); + for (i = 0; i < R; i++) + log.fine("0x" + Util.toString(rc[i])); + + log.fine("Total initialization time: " + time + " ms."); + } + } + + /** Trivial 0-arguments constructor. */ + public Whirlpool() + { + super(Registry.WHIRLPOOL_HASH, 20, BLOCK_SIZE); + } + + /** + * Private constructor for cloning purposes. + * + * @param md the instance to clone. + */ + private Whirlpool(Whirlpool md) + { + this(); + + this.H0 = md.H0; + this.H1 = md.H1; + this.H2 = md.H2; + this.H3 = md.H3; + this.H4 = md.H4; + this.H5 = md.H5; + this.H6 = md.H6; + this.H7 = md.H7; + this.count = md.count; + this.buffer = (byte[]) md.buffer.clone(); + } + + public Object clone() + { + return (new Whirlpool(this)); + } + + protected void transform(byte[] in, int offset) + { + // apply mu to the input + n0 = (in[offset++] & 0xFFL) << 56 + | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 + | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 + | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 + | (in[offset++] & 0xFFL); + n1 = (in[offset++] & 0xFFL) << 56 + | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 + | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 + | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 + | (in[offset++] & 0xFFL); + n2 = (in[offset++] & 0xFFL) << 56 + | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 + | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 + | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 + | (in[offset++] & 0xFFL); + n3 = (in[offset++] & 0xFFL) << 56 + | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 + | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 + | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 + | (in[offset++] & 0xFFL); + n4 = (in[offset++] & 0xFFL) << 56 + | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 + | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 + | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 + | (in[offset++] & 0xFFL); + n5 = (in[offset++] & 0xFFL) << 56 + | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 + | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 + | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 + | (in[offset++] & 0xFFL); + n6 = (in[offset++] & 0xFFL) << 56 + | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 + | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 + | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 + | (in[offset++] & 0xFFL); + n7 = (in[offset++] & 0xFFL) << 56 + | (in[offset++] & 0xFFL) << 48 + | (in[offset++] & 0xFFL) << 40 + | (in[offset++] & 0xFFL) << 32 + | (in[offset++] & 0xFFL) << 24 + | (in[offset++] & 0xFFL) << 16 + | (in[offset++] & 0xFFL) << 8 + | (in[offset++] & 0xFFL); + // transform K into the key schedule Kr; 0 <= r <= R + k00 = H0; + k01 = H1; + k02 = H2; + k03 = H3; + k04 = H4; + k05 = H5; + k06 = H6; + k07 = H7; + nn0 = n0 ^ k00; + nn1 = n1 ^ k01; + nn2 = n2 ^ k02; + nn3 = n3 ^ k03; + nn4 = n4 ^ k04; + nn5 = n5 ^ k05; + nn6 = n6 ^ k06; + nn7 = n7 ^ k07; + // intermediate cipher output + w0 = w1 = w2 = w3 = w4 = w5 = w6 = w7 = 0L; + for (int r = 0; r < R; r++) + { + // 1. compute intermediate round key schedule by applying ro[rc] + // to the previous round key schedule --rc being the round constant + Kr0 = T0[(int)((k00 >> 56) & 0xFFL)] + ^ T1[(int)((k07 >> 48) & 0xFFL)] + ^ T2[(int)((k06 >> 40) & 0xFFL)] + ^ T3[(int)((k05 >> 32) & 0xFFL)] + ^ T4[(int)((k04 >> 24) & 0xFFL)] + ^ T5[(int)((k03 >> 16) & 0xFFL)] + ^ T6[(int)((k02 >> 8) & 0xFFL)] + ^ T7[(int)( k01 & 0xFFL)] ^ rc[r]; + Kr1 = T0[(int)((k01 >> 56) & 0xFFL)] + ^ T1[(int)((k00 >> 48) & 0xFFL)] + ^ T2[(int)((k07 >> 40) & 0xFFL)] + ^ T3[(int)((k06 >> 32) & 0xFFL)] + ^ T4[(int)((k05 >> 24) & 0xFFL)] + ^ T5[(int)((k04 >> 16) & 0xFFL)] + ^ T6[(int)((k03 >> 8) & 0xFFL)] + ^ T7[(int)( k02 & 0xFFL)]; + Kr2 = T0[(int)((k02 >> 56) & 0xFFL)] + ^ T1[(int)((k01 >> 48) & 0xFFL)] + ^ T2[(int)((k00 >> 40) & 0xFFL)] + ^ T3[(int)((k07 >> 32) & 0xFFL)] + ^ T4[(int)((k06 >> 24) & 0xFFL)] + ^ T5[(int)((k05 >> 16) & 0xFFL)] + ^ T6[(int)((k04 >> 8) & 0xFFL)] + ^ T7[(int)( k03 & 0xFFL)]; + Kr3 = T0[(int)((k03 >> 56) & 0xFFL)] + ^ T1[(int)((k02 >> 48) & 0xFFL)] + ^ T2[(int)((k01 >> 40) & 0xFFL)] + ^ T3[(int)((k00 >> 32) & 0xFFL)] + ^ T4[(int)((k07 >> 24) & 0xFFL)] + ^ T5[(int)((k06 >> 16) & 0xFFL)] + ^ T6[(int)((k05 >> 8) & 0xFFL)] + ^ T7[(int)( k04 & 0xFFL)]; + Kr4 = T0[(int)((k04 >> 56) & 0xFFL)] + ^ T1[(int)((k03 >> 48) & 0xFFL)] + ^ T2[(int)((k02 >> 40) & 0xFFL)] + ^ T3[(int)((k01 >> 32) & 0xFFL)] + ^ T4[(int)((k00 >> 24) & 0xFFL)] + ^ T5[(int)((k07 >> 16) & 0xFFL)] + ^ T6[(int)((k06 >> 8) & 0xFFL)] + ^ T7[(int)( k05 & 0xFFL)]; + Kr5 = T0[(int)((k05 >> 56) & 0xFFL)] + ^ T1[(int)((k04 >> 48) & 0xFFL)] + ^ T2[(int)((k03 >> 40) & 0xFFL)] + ^ T3[(int)((k02 >> 32) & 0xFFL)] + ^ T4[(int)((k01 >> 24) & 0xFFL)] + ^ T5[(int)((k00 >> 16) & 0xFFL)] + ^ T6[(int)((k07 >> 8) & 0xFFL)] + ^ T7[(int)( k06 & 0xFFL)]; + Kr6 = T0[(int)((k06 >> 56) & 0xFFL)] + ^ T1[(int)((k05 >> 48) & 0xFFL)] + ^ T2[(int)((k04 >> 40) & 0xFFL)] + ^ T3[(int)((k03 >> 32) & 0xFFL)] + ^ T4[(int)((k02 >> 24) & 0xFFL)] + ^ T5[(int)((k01 >> 16) & 0xFFL)] + ^ T6[(int)((k00 >> 8) & 0xFFL)] + ^ T7[(int)( k07 & 0xFFL)]; + Kr7 = T0[(int)((k07 >> 56) & 0xFFL)] + ^ T1[(int)((k06 >> 48) & 0xFFL)] + ^ T2[(int)((k05 >> 40) & 0xFFL)] + ^ T3[(int)((k04 >> 32) & 0xFFL)] + ^ T4[(int)((k03 >> 24) & 0xFFL)] + ^ T5[(int)((k02 >> 16) & 0xFFL)] + ^ T6[(int)((k01 >> 8) & 0xFFL)] + ^ T7[(int)( k00 & 0xFFL)]; + k00 = Kr0; + k01 = Kr1; + k02 = Kr2; + k03 = Kr3; + k04 = Kr4; + k05 = Kr5; + k06 = Kr6; + k07 = Kr7; + // 2. incrementally compute the cipher output + w0 = T0[(int)((nn0 >> 56) & 0xFFL)] + ^ T1[(int)((nn7 >> 48) & 0xFFL)] + ^ T2[(int)((nn6 >> 40) & 0xFFL)] + ^ T3[(int)((nn5 >> 32) & 0xFFL)] + ^ T4[(int)((nn4 >> 24) & 0xFFL)] + ^ T5[(int)((nn3 >> 16) & 0xFFL)] + ^ T6[(int)((nn2 >> 8) & 0xFFL)] + ^ T7[(int)( nn1 & 0xFFL)] ^ Kr0; + w1 = T0[(int)((nn1 >> 56) & 0xFFL)] + ^ T1[(int)((nn0 >> 48) & 0xFFL)] + ^ T2[(int)((nn7 >> 40) & 0xFFL)] + ^ T3[(int)((nn6 >> 32) & 0xFFL)] + ^ T4[(int)((nn5 >> 24) & 0xFFL)] + ^ T5[(int)((nn4 >> 16) & 0xFFL)] + ^ T6[(int)((nn3 >> 8) & 0xFFL)] + ^ T7[(int)( nn2 & 0xFFL)] ^ Kr1; + w2 = T0[(int)((nn2 >> 56) & 0xFFL)] + ^ T1[(int)((nn1 >> 48) & 0xFFL)] + ^ T2[(int)((nn0 >> 40) & 0xFFL)] + ^ T3[(int)((nn7 >> 32) & 0xFFL)] + ^ T4[(int)((nn6 >> 24) & 0xFFL)] + ^ T5[(int)((nn5 >> 16) & 0xFFL)] + ^ T6[(int)((nn4 >> 8) & 0xFFL)] + ^ T7[(int)( nn3 & 0xFFL)] ^ Kr2; + w3 = T0[(int)((nn3 >> 56) & 0xFFL)] + ^ T1[(int)((nn2 >> 48) & 0xFFL)] + ^ T2[(int)((nn1 >> 40) & 0xFFL)] + ^ T3[(int)((nn0 >> 32) & 0xFFL)] + ^ T4[(int)((nn7 >> 24) & 0xFFL)] + ^ T5[(int)((nn6 >> 16) & 0xFFL)] + ^ T6[(int)((nn5 >> 8) & 0xFFL)] + ^ T7[(int)( nn4 & 0xFFL)] ^ Kr3; + w4 = T0[(int)((nn4 >> 56) & 0xFFL)] + ^ T1[(int)((nn3 >> 48) & 0xFFL)] + ^ T2[(int)((nn2 >> 40) & 0xFFL)] + ^ T3[(int)((nn1 >> 32) & 0xFFL)] + ^ T4[(int)((nn0 >> 24) & 0xFFL)] + ^ T5[(int)((nn7 >> 16) & 0xFFL)] + ^ T6[(int)((nn6 >> 8) & 0xFFL)] + ^ T7[(int)( nn5 & 0xFFL)] ^ Kr4; + w5 = T0[(int)((nn5 >> 56) & 0xFFL)] + ^ T1[(int)((nn4 >> 48) & 0xFFL)] + ^ T2[(int)((nn3 >> 40) & 0xFFL)] + ^ T3[(int)((nn2 >> 32) & 0xFFL)] + ^ T4[(int)((nn1 >> 24) & 0xFFL)] + ^ T5[(int)((nn0 >> 16) & 0xFFL)] + ^ T6[(int)((nn7 >> 8) & 0xFFL)] + ^ T7[(int)( nn6 & 0xFFL)] ^ Kr5; + w6 = T0[(int)((nn6 >> 56) & 0xFFL)] + ^ T1[(int)((nn5 >> 48) & 0xFFL)] + ^ T2[(int)((nn4 >> 40) & 0xFFL)] + ^ T3[(int)((nn3 >> 32) & 0xFFL)] + ^ T4[(int)((nn2 >> 24) & 0xFFL)] + ^ T5[(int)((nn1 >> 16) & 0xFFL)] + ^ T6[(int)((nn0 >> 8) & 0xFFL)] + ^ T7[(int)( nn7 & 0xFFL)] ^ Kr6; + w7 = T0[(int)((nn7 >> 56) & 0xFFL)] + ^ T1[(int)((nn6 >> 48) & 0xFFL)] + ^ T2[(int)((nn5 >> 40) & 0xFFL)] + ^ T3[(int)((nn4 >> 32) & 0xFFL)] + ^ T4[(int)((nn3 >> 24) & 0xFFL)] + ^ T5[(int)((nn2 >> 16) & 0xFFL)] + ^ T6[(int)((nn1 >> 8) & 0xFFL)] + ^ T7[(int)( nn0 & 0xFFL)] ^ Kr7; + nn0 = w0; + nn1 = w1; + nn2 = w2; + nn3 = w3; + nn4 = w4; + nn5 = w5; + nn6 = w6; + nn7 = w7; + } + // apply the Miyaguchi-Preneel hash scheme + H0 ^= w0 ^ n0; + H1 ^= w1 ^ n1; + H2 ^= w2 ^ n2; + H3 ^= w3 ^ n3; + H4 ^= w4 ^ n4; + H5 ^= w5 ^ n5; + H6 ^= w6 ^ n6; + H7 ^= w7 ^ n7; + } + + protected byte[] padBuffer() + { + // [WHIRLPOOL] p. 6: + // "...padded with a 1-bit, then with as few 0-bits as necessary to + // obtain a bit string whose length is an odd multiple of 256, and + // finally with the 256-bit right-justified binary representation of L." + // in this implementation we use 'count' as the number of bytes hashed + // so far. hence the minimal number of bytes added to the message proper + // are 33 (1 for the 1-bit followed by the 0-bits and the encoding of + // the count framed in a 256-bit block). our formula is then: + // count + 33 + padding = 0 (mod BLOCK_SIZE) + int n = (int)((count + 33) % BLOCK_SIZE); + int padding = n == 0 ? 33 : BLOCK_SIZE - n + 33; + byte[] result = new byte[padding]; + // padding is always binary 1 followed by binary 0s + result[0] = (byte) 0x80; + // save (right justified) the number of bits hashed + long bits = count * 8; + int i = padding - 8; + result[i++] = (byte)(bits >>> 56); + result[i++] = (byte)(bits >>> 48); + result[i++] = (byte)(bits >>> 40); + result[i++] = (byte)(bits >>> 32); + result[i++] = (byte)(bits >>> 24); + result[i++] = (byte)(bits >>> 16); + result[i++] = (byte)(bits >>> 8); + result[i ] = (byte) bits; + return result; + } + + protected byte[] getResult() + { + // apply inverse mu to the context + return new byte[] { + (byte)(H0 >>> 56), (byte)(H0 >>> 48), (byte)(H0 >>> 40), (byte)(H0 >>> 32), + (byte)(H0 >>> 24), (byte)(H0 >>> 16), (byte)(H0 >>> 8), (byte) H0, + (byte)(H1 >>> 56), (byte)(H1 >>> 48), (byte)(H1 >>> 40), (byte)(H1 >>> 32), + (byte)(H1 >>> 24), (byte)(H1 >>> 16), (byte)(H1 >>> 8), (byte) H1, + (byte)(H2 >>> 56), (byte)(H2 >>> 48), (byte)(H2 >>> 40), (byte)(H2 >>> 32), + (byte)(H2 >>> 24), (byte)(H2 >>> 16), (byte)(H2 >>> 8), (byte) H2, + (byte)(H3 >>> 56), (byte)(H3 >>> 48), (byte)(H3 >>> 40), (byte)(H3 >>> 32), + (byte)(H3 >>> 24), (byte)(H3 >>> 16), (byte)(H3 >>> 8), (byte) H3, + (byte)(H4 >>> 56), (byte)(H4 >>> 48), (byte)(H4 >>> 40), (byte)(H4 >>> 32), + (byte)(H4 >>> 24), (byte)(H4 >>> 16), (byte)(H4 >>> 8), (byte) H4, + (byte)(H5 >>> 56), (byte)(H5 >>> 48), (byte)(H5 >>> 40), (byte)(H5 >>> 32), + (byte)(H5 >>> 24), (byte)(H5 >>> 16), (byte)(H5 >>> 8), (byte) H5, + (byte)(H6 >>> 56), (byte)(H6 >>> 48), (byte)(H6 >>> 40), (byte)(H6 >>> 32), + (byte)(H6 >>> 24), (byte)(H6 >>> 16), (byte)(H6 >>> 8), (byte) H6, + (byte)(H7 >>> 56), (byte)(H7 >>> 48), (byte)(H7 >>> 40), (byte)(H7 >>> 32), + (byte)(H7 >>> 24), (byte)(H7 >>> 16), (byte)(H7 >>> 8), (byte) H7 }; + + } + + protected void resetContext() + { + H0 = H1 = H2 = H3 = H4 = H5 = H6 = H7 = 0L; + } + + public boolean selfTest() + { + if (valid == null) + { + String d = Util.toString(new Whirlpool().digest()); + valid = Boolean.valueOf(DIGEST0.equals(d)); + } + return valid.booleanValue(); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/HavalSpi.java b/libjava/classpath/gnu/java/security/jce/hash/HavalSpi.java new file mode 100644 index 000000000..7c0a6027b --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/HavalSpi.java @@ -0,0 +1,54 @@ +/* HavalSpi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the HAVAL Service Provider Interface + * (SPI) adapter. + */ +public class HavalSpi + extends MessageDigestAdapter +{ + public HavalSpi() + { + super(Registry.HAVAL_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/MD2Spi.java b/libjava/classpath/gnu/java/security/jce/hash/MD2Spi.java new file mode 100644 index 000000000..76def7acb --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/MD2Spi.java @@ -0,0 +1,55 @@ +/* MD2Spi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the MD2 Service Provider Interface (SPI) + * adapter. + */ +public class MD2Spi + extends MessageDigestAdapter +{ + /** Trivial 0-arguments constructor. */ + public MD2Spi() + { + super(Registry.MD2_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/MD4Spi.java b/libjava/classpath/gnu/java/security/jce/hash/MD4Spi.java new file mode 100644 index 000000000..125943d30 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/MD4Spi.java @@ -0,0 +1,55 @@ +/* MD4Spi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the MD4 Service Provider Interface (SPI) + * adapter. + */ +public class MD4Spi + extends MessageDigestAdapter +{ + /** Trivial 0-arguments constructor. */ + public MD4Spi() + { + super(Registry.MD4_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/MD5Spi.java b/libjava/classpath/gnu/java/security/jce/hash/MD5Spi.java new file mode 100644 index 000000000..25d9240b4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/MD5Spi.java @@ -0,0 +1,54 @@ +/* MD5Spi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the MD5 Service Provider Interface (SPI) + * adapter. + */ +public class MD5Spi + extends MessageDigestAdapter +{ + public MD5Spi() + { + super(Registry.MD5_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/MessageDigestAdapter.java b/libjava/classpath/gnu/java/security/jce/hash/MessageDigestAdapter.java new file mode 100644 index 000000000..2651ecf92 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/MessageDigestAdapter.java @@ -0,0 +1,133 @@ +/* MessageDigestAdapter.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.hash.HashFactory; + +import java.security.DigestException; +import java.security.MessageDigestSpi; + +/** + * The implementation of a generic {@link java.security.MessageDigest} adapter + * class to wrap GNU hash instances. + *

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

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

+ * All the implementations which subclass this object, and which are serviced by + * the GNU provider implement the {@link Cloneable} interface. + */ +class MessageDigestAdapter + extends MessageDigestSpi + implements Cloneable +{ + /** Our underlying hash instance. */ + private IMessageDigest adaptee; + + /** + * Trivial protected constructor. + * + * @param mdName the canonical name of the hash algorithm. + */ + protected MessageDigestAdapter(String mdName) + { + this(HashFactory.getInstance(mdName)); + } + + /** + * Private constructor for cloning purposes. + * + * @param adaptee a clone of the underlying hash algorithm instance. + */ + private MessageDigestAdapter(IMessageDigest adaptee) + { + super(); + + this.adaptee = adaptee; + } + + public Object clone() + { + return new MessageDigestAdapter((IMessageDigest) adaptee.clone()); + } + + public int engineGetDigestLength() + { + return adaptee.hashSize(); + } + + public void engineUpdate(byte input) + { + adaptee.update(input); + } + + public void engineUpdate(byte[] input, int offset, int len) + { + adaptee.update(input, offset, len); + } + + public byte[] engineDigest() + { + return adaptee.digest(); + } + + public int engineDigest(byte[] buf, int offset, int len) + throws DigestException + { + int result = adaptee.hashSize(); + if (len < result) + throw new DigestException(); + + byte[] md = adaptee.digest(); + System.arraycopy(md, 0, buf, offset, result); + return result; + } + + public void engineReset() + { + adaptee.reset(); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/RipeMD128Spi.java b/libjava/classpath/gnu/java/security/jce/hash/RipeMD128Spi.java new file mode 100644 index 000000000..499996c02 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/RipeMD128Spi.java @@ -0,0 +1,54 @@ +/* RipeMD128Spi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the RIPEMD-128 Service Provider Interface + * (SPI) adapter. + */ +public class RipeMD128Spi + extends MessageDigestAdapter +{ + public RipeMD128Spi() + { + super(Registry.RIPEMD128_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/RipeMD160Spi.java b/libjava/classpath/gnu/java/security/jce/hash/RipeMD160Spi.java new file mode 100644 index 000000000..a62bea6c0 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/RipeMD160Spi.java @@ -0,0 +1,54 @@ +/* RipeMD160Spi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the RIPEMD-160 Service Provider Interface + * (SPI) adapter. + */ +public class RipeMD160Spi + extends MessageDigestAdapter +{ + public RipeMD160Spi() + { + super(Registry.RIPEMD160_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/Sha160Spi.java b/libjava/classpath/gnu/java/security/jce/hash/Sha160Spi.java new file mode 100644 index 000000000..ea2dfe24c --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/Sha160Spi.java @@ -0,0 +1,54 @@ +/* Sha160Spi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the SHA-1 (160-bit) Service Provider Interface + * (SPI) adapter. + */ +public class Sha160Spi + extends MessageDigestAdapter +{ + public Sha160Spi() + { + super(Registry.SHA160_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/Sha256Spi.java b/libjava/classpath/gnu/java/security/jce/hash/Sha256Spi.java new file mode 100644 index 000000000..39d31d07b --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/Sha256Spi.java @@ -0,0 +1,54 @@ +/* Sha256Spi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the SHA-2-1 (256-bit) Service Provider Interface + * (SPI) adapter. + */ +public class Sha256Spi + extends MessageDigestAdapter +{ + public Sha256Spi() + { + super(Registry.SHA256_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/Sha384Spi.java b/libjava/classpath/gnu/java/security/jce/hash/Sha384Spi.java new file mode 100644 index 000000000..fa1e3f948 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/Sha384Spi.java @@ -0,0 +1,54 @@ +/* Sha384Spi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the SHA-2-2 (384-bit) Service Provider Interface + * (SPI) adapter. + */ +public class Sha384Spi + extends MessageDigestAdapter +{ + public Sha384Spi() + { + super(Registry.SHA384_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/Sha512Spi.java b/libjava/classpath/gnu/java/security/jce/hash/Sha512Spi.java new file mode 100644 index 000000000..4bd39daed --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/Sha512Spi.java @@ -0,0 +1,54 @@ +/* Sha512Spi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the SHA-2-3 (512-bit) Service Provider Interface + * (SPI) adapter. + */ +public class Sha512Spi + extends MessageDigestAdapter +{ + public Sha512Spi() + { + super(Registry.SHA512_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/TigerSpi.java b/libjava/classpath/gnu/java/security/jce/hash/TigerSpi.java new file mode 100644 index 000000000..3d38c847f --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/TigerSpi.java @@ -0,0 +1,55 @@ +/* TigerSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the Tiger Service Provider Interface + * (SPI) adapter. + */ +public class TigerSpi + extends MessageDigestAdapter +{ + /** Trivial 0-arguments constructor. */ + public TigerSpi() + { + super(Registry.TIGER_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/hash/WhirlpoolSpi.java b/libjava/classpath/gnu/java/security/jce/hash/WhirlpoolSpi.java new file mode 100644 index 000000000..68a3a7059 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/hash/WhirlpoolSpi.java @@ -0,0 +1,54 @@ +/* WhirlpoolSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.hash; + +import gnu.java.security.Registry; + +/** + * The implementation of the Whirlpool Service Provider Interface + * (SPI) adapter. + */ +public class WhirlpoolSpi + extends MessageDigestAdapter +{ + public WhirlpoolSpi() + { + super(Registry.WHIRLPOOL_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/HavalRandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/HavalRandomSpi.java new file mode 100644 index 000000000..ebf80f2d7 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/HavalRandomSpi.java @@ -0,0 +1,54 @@ +/* HavalRandomSpi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the HAVAL-based SecureRandom Service Provider + * Interface (SPI) adapter. + */ +public class HavalRandomSpi + extends SecureRandomAdapter +{ + public HavalRandomSpi() + { + super(Registry.HAVAL_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/MD2RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/MD2RandomSpi.java new file mode 100644 index 000000000..8b9abe4e9 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/MD2RandomSpi.java @@ -0,0 +1,54 @@ +/* MD2RandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the MD2-based SecureRandom Service Provider + * Interface (SPI) adapter. + */ +public class MD2RandomSpi + extends SecureRandomAdapter +{ + public MD2RandomSpi() + { + super(Registry.MD2_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/MD4RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/MD4RandomSpi.java new file mode 100644 index 000000000..2a71d6a0d --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/MD4RandomSpi.java @@ -0,0 +1,54 @@ +/* MD4RandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the MD4-based SecureRandom Service Provider + * Interface (SPI) adapter. + */ +public class MD4RandomSpi + extends SecureRandomAdapter +{ + public MD4RandomSpi() + { + super(Registry.MD4_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/MD5RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/MD5RandomSpi.java new file mode 100644 index 000000000..8fb50e16f --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/MD5RandomSpi.java @@ -0,0 +1,54 @@ +/* MD5RandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the MD5-based SecureRandom Service Provider + * Interface (SPI) adapter. + */ +public class MD5RandomSpi + extends SecureRandomAdapter +{ + public MD5RandomSpi() + { + super(Registry.MD5_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/RipeMD128RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/RipeMD128RandomSpi.java new file mode 100644 index 000000000..6f8dde0e0 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/RipeMD128RandomSpi.java @@ -0,0 +1,54 @@ +/* RipeMD128RandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the RIPEMD128-based SecureRandom Service Provider + * Interface (SPI) adapter. + */ +public class RipeMD128RandomSpi + extends SecureRandomAdapter +{ + public RipeMD128RandomSpi() + { + super(Registry.RIPEMD128_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/RipeMD160RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/RipeMD160RandomSpi.java new file mode 100644 index 000000000..6bb4e2b50 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/RipeMD160RandomSpi.java @@ -0,0 +1,54 @@ +/* RipeMD160RandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the RIPEMD160-based SecureRandom Service Provider + * Interface (SPI) adapter. + */ +public class RipeMD160RandomSpi + extends SecureRandomAdapter +{ + public RipeMD160RandomSpi() + { + super(Registry.RIPEMD160_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/SecureRandomAdapter.java b/libjava/classpath/gnu/java/security/jce/prng/SecureRandomAdapter.java new file mode 100644 index 000000000..9307cfa7f --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/SecureRandomAdapter.java @@ -0,0 +1,184 @@ +/* SecureRandomAdapter.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.action.GetSecurityPropertyAction; +import gnu.classpath.SystemProperties; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.prng.MDGenerator; + +import java.security.AccessController; +import java.security.SecureRandom; +import java.security.SecureRandomSpi; + +import java.util.Collections; +import java.util.logging.Level; +import java.util.logging.Logger; + +import java.io.InputStream; +import java.io.IOException; + +import java.net.MalformedURLException; +import java.net.URL; + +/** + *

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

+ * + *

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

+ * + *

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

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

Trivial protected constructor.

+ * + * @param mdName the canonical name of the underlying hash algorithm. + */ + protected SecureRandomAdapter(String mdName) + { + super(); + + this.mdName = mdName; + adaptee.init (Collections.singletonMap (MDGenerator.MD_NAME, mdName)); + } + + public static final byte[] getSeed(int numBytes) + { + URL sourceUrl = null; + String urlStr = null; + + byte[] buffer = new byte[numBytes]; + + GetSecurityPropertyAction action = + new GetSecurityPropertyAction(SECURERANDOM_SOURCE); + try + { + urlStr = (String) AccessController.doPrivileged(action); + if (urlStr != null) + sourceUrl = new URL(urlStr); + } + catch (MalformedURLException ignored) + { + logger.log(Level.WARNING, + SECURERANDOM_SOURCE + " property is malformed: {0}", + urlStr); + } + + if (sourceUrl == null) + { + try + { + urlStr = SystemProperties.getProperty(JAVA_SECURITY_EGD); + if (urlStr != null) + sourceUrl = new URL(urlStr); + } + catch (MalformedURLException mue) + { + logger.log(Level.WARNING, + JAVA_SECURITY_EGD + " property is malformed: {0}", + urlStr); + } + } + + if (sourceUrl != null) + { + try + { + InputStream in = sourceUrl.openStream(); + in.read(buffer); + return buffer; + } + catch (IOException ioe) + { + logger.log(Level.FINE, "error reading random bytes", ioe); + } + } + + // If we get here, we did not get any seed from a property URL. + VMSecureRandom.generateSeed(buffer, 0, buffer.length); + return buffer; + } + + public byte[] engineGenerateSeed(int numBytes) + { + return getSeed(numBytes); + } + + public void engineNextBytes(byte[] bytes) + { + if (!isSeeded) + { + engineSetSeed(engineGenerateSeed(32)); + } + try + { + adaptee.nextBytes(bytes, 0, bytes.length); + } + catch (LimitReachedException ignored) + { + } + } + + public void engineSetSeed(byte[] seed) + { + adaptee.addRandomBytes (seed); + isSeeded = true; + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/Sha160RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/Sha160RandomSpi.java new file mode 100644 index 000000000..ba4d22265 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/Sha160RandomSpi.java @@ -0,0 +1,54 @@ +/* Sha160RandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the SHA1-based SecureRandom Service Provider + * Interface (SPI) adapter. + */ +public class Sha160RandomSpi + extends SecureRandomAdapter +{ + public Sha160RandomSpi() + { + super(Registry.SHA160_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/Sha256RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/Sha256RandomSpi.java new file mode 100644 index 000000000..a6ddb70af --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/Sha256RandomSpi.java @@ -0,0 +1,54 @@ +/* Sha256RandomSpi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the SHA-256 based SecureRandom Service Provider + * Interface (SPI) adapter. + */ +public class Sha256RandomSpi + extends SecureRandomAdapter +{ + public Sha256RandomSpi() + { + super(Registry.SHA256_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/Sha384RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/Sha384RandomSpi.java new file mode 100644 index 000000000..4954b1be7 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/Sha384RandomSpi.java @@ -0,0 +1,54 @@ +/* Sha384RandomSpi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the SHA-384 based SecureRandom Service Provider + * Interface (SPI) adapter. + */ +public class Sha384RandomSpi + extends SecureRandomAdapter +{ + public Sha384RandomSpi() + { + super(Registry.SHA384_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/Sha512RandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/Sha512RandomSpi.java new file mode 100644 index 000000000..27de7f319 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/Sha512RandomSpi.java @@ -0,0 +1,54 @@ +/* Sha512RandomSpi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the SHA-512 based SecureRandom Service Provider + * Interface (SPI) adapter. + */ +public class Sha512RandomSpi + extends SecureRandomAdapter +{ + public Sha512RandomSpi() + { + super(Registry.SHA512_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/TigerRandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/TigerRandomSpi.java new file mode 100644 index 000000000..722ab3279 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/TigerRandomSpi.java @@ -0,0 +1,54 @@ +/* TigerRandomSpi.java -- + Copyright (C) 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the Tiger based SecureRandom Service Provider + * Interface (SPI) adapter. + */ +public class TigerRandomSpi + extends SecureRandomAdapter +{ + public TigerRandomSpi() + { + super(Registry.TIGER_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java b/libjava/classpath/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java new file mode 100644 index 000000000..5da43d77e --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/prng/WhirlpoolRandomSpi.java @@ -0,0 +1,54 @@ +/* WhirlpoolRandomSpi.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.prng; + +import gnu.java.security.Registry; + +/** + * The implementation of the Whirlpool-based SecureRandom Service Provider + * Interface (SPI) adapter. + */ +public class WhirlpoolRandomSpi + extends SecureRandomAdapter +{ + public WhirlpoolRandomSpi() + { + super(Registry.WHIRLPOOL_HASH); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/DSSKeyFactory.java b/libjava/classpath/gnu/java/security/jce/sig/DSSKeyFactory.java new file mode 100644 index 000000000..ec993432c --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/DSSKeyFactory.java @@ -0,0 +1,221 @@ +/* DSSKeyFactory.java -- JCE DSA key factory Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSKeyPairPKCS8Codec; +import gnu.java.security.key.dss.DSSKeyPairX509Codec; +import gnu.java.security.key.dss.DSSPrivateKey; +import gnu.java.security.key.dss.DSSPublicKey; + +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.DSAPrivateKey; +import java.security.interfaces.DSAPublicKey; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.DSAPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; + +/** + * DSA key factory. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class DSSKeyFactory + extends KeyFactorySpi +{ + // implicit 0-arguments constructor + + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof DSAPublicKeySpec) + { + DSAPublicKeySpec spec = (DSAPublicKeySpec) keySpec; + BigInteger p = spec.getP(); + BigInteger q = spec.getQ(); + BigInteger g = spec.getG(); + BigInteger y = spec.getY(); + return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y); + } + if (keySpec instanceof X509EncodedKeySpec) + { + X509EncodedKeySpec spec = (X509EncodedKeySpec) keySpec; + byte[] encoded = spec.getEncoded(); + PublicKey result; + try + { + result = new DSSKeyPairX509Codec().decodePublicKey(encoded); + return result; + } + catch (RuntimeException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + throw new InvalidKeySpecException("Unsupported (public) key specification"); + } + + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + if (keySpec instanceof DSAPrivateKeySpec) + { + DSAPrivateKeySpec spec = (DSAPrivateKeySpec) keySpec; + BigInteger p = spec.getP(); + BigInteger q = spec.getQ(); + BigInteger g = spec.getG(); + BigInteger x = spec.getX(); + return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x); + } + if (keySpec instanceof PKCS8EncodedKeySpec) + { + PKCS8EncodedKeySpec spec = (PKCS8EncodedKeySpec) keySpec; + byte[] encoded = spec.getEncoded(); + PrivateKey result; + try + { + result = new DSSKeyPairPKCS8Codec().decodePrivateKey(encoded); + return result; + } + catch (RuntimeException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + throw new InvalidKeySpecException("Unsupported (private) key specification"); + } + + protected KeySpec engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + if (key instanceof DSAPublicKey) + { + if (keySpec.isAssignableFrom(DSAPublicKeySpec.class)) + { + DSAPublicKey dsaKey = (DSAPublicKey) key; + BigInteger p = dsaKey.getParams().getP(); + BigInteger q = dsaKey.getParams().getQ(); + BigInteger g = dsaKey.getParams().getG(); + BigInteger y = dsaKey.getY(); + return new DSAPublicKeySpec(y, p, q, g); + } + if (keySpec.isAssignableFrom(X509EncodedKeySpec.class)) + { + if (key instanceof DSSPublicKey) + { + DSSPublicKey dssKey = (DSSPublicKey) key; + byte[] encoded = dssKey.getEncoded(Registry.X509_ENCODING_ID); + return new X509EncodedKeySpec(encoded); + } + if (Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat())) + { + byte[] encoded = key.getEncoded(); + return new X509EncodedKeySpec(encoded); + } + throw new InvalidKeySpecException( + "Wrong key type or unsupported (public) key specification"); + } + throw new InvalidKeySpecException("Unsupported (public) key specification"); + } + if (key instanceof DSAPrivateKey) + { + if (keySpec.isAssignableFrom(DSAPrivateKeySpec.class)) + { + DSAPrivateKey dsaKey = (DSAPrivateKey) key; + BigInteger p = dsaKey.getParams().getP(); + BigInteger q = dsaKey.getParams().getQ(); + BigInteger g = dsaKey.getParams().getG(); + BigInteger x = dsaKey.getX(); + return new DSAPrivateKeySpec(x, p, q, g); + } + if (keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) + { + if (key instanceof DSSPrivateKey) + { + DSSPrivateKey dssKey = (DSSPrivateKey) key; + byte[] encoded = dssKey.getEncoded(Registry.PKCS8_ENCODING_ID); + return new PKCS8EncodedKeySpec(encoded); + } + if (Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat())) + { + byte[] encoded = key.getEncoded(); + return new PKCS8EncodedKeySpec(encoded); + } + throw new InvalidKeySpecException( + "Wrong key type or unsupported (private) key specification"); + } + throw new InvalidKeySpecException("Unsupported (private) key specification"); + } + throw new InvalidKeySpecException("Wrong key type or unsupported key specification"); + } + + protected Key engineTranslateKey(Key key) throws InvalidKeyException + { + if ((key instanceof DSSPublicKey) || (key instanceof DSSPrivateKey)) + return key; + + if (key instanceof DSAPublicKey) + { + DSAPublicKey dsaKey = (DSAPublicKey) key; + BigInteger p = dsaKey.getParams().getP(); + BigInteger q = dsaKey.getParams().getQ(); + BigInteger g = dsaKey.getParams().getG(); + BigInteger y = dsaKey.getY(); + return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y); + } + if (key instanceof DSAPrivateKey) + { + DSAPrivateKey dsaKey = (DSAPrivateKey) key; + BigInteger p = dsaKey.getParams().getP(); + BigInteger q = dsaKey.getParams().getQ(); + BigInteger g = dsaKey.getParams().getG(); + BigInteger x = dsaKey.getX(); + return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x); + } + throw new InvalidKeyException("Wrong key type"); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java b/libjava/classpath/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java new file mode 100644 index 000000000..2d33e1621 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/DSSKeyPairGeneratorSpi.java @@ -0,0 +1,146 @@ +/* DSSKeyPairGeneratorSpi.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSKeyPairGenerator; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.SecureRandom; +import java.security.interfaces.DSAKeyPairGenerator; +import java.security.interfaces.DSAParams; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.DSAParameterSpec; +import java.util.HashMap; + +/** + * The implementation of a {@link java.security.KeyPairGenerator} adapter class + * to wrap GNU DSS keypair generator instances. + *

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

+   *   DssParams ::= SEQUENCE {
+   *     p   INTEGER,
+   *     q   INTEGER,
+   *     g   INTEGER
+   *   }
+   * 
+ */ + protected void engineInit(byte[] params) throws IOException + { + DERReader der = new DERReader(params); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + } + + protected void engineInit(byte[] params, String format) throws IOException + { + if (format != null) + { + format = format.trim(); + if (format.length() == 0) + throw new IOException("Format MUST NOT be an empty string"); + + if (! format.equalsIgnoreCase(Registry.ASN1_ENCODING_SHORT_NAME)) + throw new IOException("Unknown or unsupported format: " + format); + } + engineInit(params); + } + + protected AlgorithmParameterSpec engineGetParameterSpec(Class paramSpec) + throws InvalidParameterSpecException + { + if (! paramSpec.isAssignableFrom(DSAParameterSpec.class)) + throw new InvalidParameterSpecException("Wrong AlgorithmParameterSpec type: " + + paramSpec.getName()); + return new DSAParameterSpec(p, q, g); + } + + /** + * Encodes the set of DSS parameters as per RFC-2459; i.e. as the DER-encoded + * form of the following ASN.1 construct: + * + *
+   *   DssParams ::= SEQUENCE {
+   *     p   INTEGER,
+   *     q   INTEGER,
+   *     g   INTEGER
+   *   }
+   * 
+ */ + protected byte[] engineGetEncoded() throws IOException + { + DERValue derP = new DERValue(DER.INTEGER, p); + DERValue derQ = new DERValue(DER.INTEGER, q); + DERValue derG = new DERValue(DER.INTEGER, g); + + ArrayList params = new ArrayList(3); + params.add(derP); + params.add(derQ); + params.add(derG); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + DERWriter.write(baos, derParams); + byte[] result = baos.toByteArray(); + + return result; + } + + protected byte[] engineGetEncoded(String format) throws IOException + { + if (format != null) + { + format = format.trim(); + if (format.length() == 0) + throw new IOException("Format MUST NOT be an empty string"); + + if (! format.equalsIgnoreCase(Registry.ASN1_ENCODING_SHORT_NAME)) + throw new IOException("Unknown or unsupported format: " + format); + } + return engineGetEncoded(); + } + + protected String engineToString() + { + CPStringBuilder sb = new CPStringBuilder("p="); + if (p == null) + sb.append("???"); + else + sb.append("0x").append(p.toString(16)); + + sb.append(", q="); + if (q == null) + sb.append("???"); + else + sb.append("0x").append(q.toString(16)); + + sb.append(", g="); + if (g == null) + sb.append("???"); + else + sb.append("0x").append(g.toString(16)); + + return sb.toString(); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/DSSParametersGenerator.java b/libjava/classpath/gnu/java/security/jce/sig/DSSParametersGenerator.java new file mode 100644 index 000000000..09c138610 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/DSSParametersGenerator.java @@ -0,0 +1,125 @@ +/* DSSParametersGenerator.java -- JCE Adapter for a generator of DSS parameters + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSKeyPairGenerator; +import gnu.java.security.key.dss.FIPS186; +import gnu.java.security.provider.Gnu; + +import java.math.BigInteger; +import java.security.AlgorithmParameterGeneratorSpi; +import java.security.AlgorithmParameters; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidParameterException; +import java.security.NoSuchAlgorithmException; +import java.security.Provider; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; +import java.security.spec.DSAParameterSpec; +import java.security.spec.InvalidParameterSpecException; + +/** + * A JCE Adapter for a generator of DSS parameters. + */ +public class DSSParametersGenerator + extends AlgorithmParameterGeneratorSpi +{ + private static final Provider GNU = new Gnu(); + + /** Size of the public modulus in bits. */ + private int modulusLength = -1; + + /** User specified source of randomness. */ + private SecureRandom rnd; + + /** Our concrete DSS parameters generator. */ + private FIPS186 fips; + + // default 0-arguments constructor + + protected void engineInit(int size, SecureRandom random) + { + if ((size % 64) != 0 || size < 512 || size > 1024) + throw new InvalidParameterException("Modulus size/length (in bits) MUST " + + "be a multiple of 64, greater than " + + "or equal to 512, and less than or " + + "equal to 1024"); + this.modulusLength = size; + this.rnd = random; + } + + protected void engineInit(AlgorithmParameterSpec spec, SecureRandom random) + throws InvalidAlgorithmParameterException + { + if (! (spec instanceof DSAParameterSpec)) + throw new InvalidAlgorithmParameterException("Wrong AlgorithmParameterSpec type: " + + spec.getClass().getName()); + DSAParameterSpec dsaSpec = (DSAParameterSpec) spec; + BigInteger p = dsaSpec.getP(); + int size = p.bitLength(); + this.engineInit(size, random); + } + + protected AlgorithmParameters engineGenerateParameters() + { + if (modulusLength < 1) + modulusLength = DSSKeyPairGenerator.DEFAULT_MODULUS_LENGTH; + + fips = new FIPS186(modulusLength, rnd); + BigInteger[] params = fips.generateParameters(); + BigInteger p = params[3]; + BigInteger q = params[2]; + BigInteger g = params[5]; + DSAParameterSpec spec = new DSAParameterSpec(p, q, g); + AlgorithmParameters result = null; + try + { + result = AlgorithmParameters.getInstance(Registry.DSS_KPG, GNU); + result.init(spec); + } + catch (NoSuchAlgorithmException ignore) + { + } + catch (InvalidParameterSpecException ignore) + { + } + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/DSSRawSignatureSpi.java b/libjava/classpath/gnu/java/security/jce/sig/DSSRawSignatureSpi.java new file mode 100644 index 000000000..edee4e577 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/DSSRawSignatureSpi.java @@ -0,0 +1,56 @@ +/* DSSRawSignatureSpi.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.dss.DSSSignatureRawCodec; + +/** + * The implementation of Service Provider Interface (SPI) + * adapter for the DSS (Digital Signature Standard) signature scheme, encoded + * and/or decoded in RAW format. + */ +public class DSSRawSignatureSpi + extends SignatureAdapter +{ + public DSSRawSignatureSpi() + { + super(Registry.DSS_SIG, new DSSSignatureRawCodec()); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/EncodedKeyFactory.java b/libjava/classpath/gnu/java/security/jce/sig/EncodedKeyFactory.java new file mode 100644 index 000000000..19ec088c5 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/EncodedKeyFactory.java @@ -0,0 +1,430 @@ +/* EncodedKeyFactory.java -- JCE Encoded key factory Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSPrivateKey; +import gnu.java.security.key.dss.DSSPublicKey; +import gnu.java.security.key.rsa.GnuRSAPrivateKey; +import gnu.java.security.key.rsa.GnuRSAPublicKey; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.math.BigInteger; +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.Key; +import java.security.KeyFactorySpi; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.DSAPrivateKeySpec; +import java.security.spec.DSAPublicKeySpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.KeySpec; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.RSAPrivateCrtKeySpec; +import java.security.spec.RSAPublicKeySpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.logging.Level; +import java.util.logging.Logger; + +import javax.crypto.interfaces.DHPrivateKey; +import javax.crypto.interfaces.DHPublicKey; +import javax.crypto.spec.DHPrivateKeySpec; +import javax.crypto.spec.DHPublicKeySpec; + +/** + * A factory for keys encoded in either the X.509 format (for public keys) or + * the PKCS#8 format (for private keys). + */ +public class EncodedKeyFactory + extends KeyFactorySpi +{ + private static final Logger log = Logger.getLogger(EncodedKeyFactory.class.getName()); + + private static Object invokeConstructor(String className, Object[] params) + throws InvalidKeySpecException + { + Class clazz = getConcreteClass(className); + try + { + Constructor ctor = getConcreteCtor(clazz); + Object result = ctor.newInstance(params); + return result; + } + catch (InstantiationException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + catch (IllegalAccessException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + catch (InvocationTargetException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + + private static Class getConcreteClass(String className) + throws InvalidKeySpecException + { + try + { + Class result = Class.forName(className); + return result; + } + catch (ClassNotFoundException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + + private static Constructor getConcreteCtor(Class clazz) + throws InvalidKeySpecException + { + try + { + Constructor result = clazz.getConstructor(new Class[] {int.class, + BigInteger.class, + BigInteger.class, + BigInteger.class, + BigInteger.class}); + return result; + } + catch (NoSuchMethodException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + + private static Object invokeValueOf(String className, byte[] encoded) + throws InvalidKeySpecException + { + Class clazz = getConcreteClass(className); + try + { + Method valueOf = getValueOfMethod(clazz); + Object result = valueOf.invoke(null, new Object[] { encoded }); + return result; + } + catch (IllegalAccessException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + catch (InvocationTargetException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + + private static Method getValueOfMethod(Class clazz) + throws InvalidKeySpecException + { + try + { + Method result = clazz.getMethod("valueOf", new Class[] {byte[].class}); + return result; + } + catch (NoSuchMethodException x) + { + throw new InvalidKeySpecException(x.getMessage(), x); + } + } + + protected PublicKey engineGeneratePublic(KeySpec keySpec) + throws InvalidKeySpecException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGeneratePublic()", keySpec); + PublicKey result = null; + if (keySpec instanceof DSAPublicKeySpec) + result = decodeDSSPublicKey((DSAPublicKeySpec) keySpec); + else if (keySpec instanceof RSAPublicKeySpec) + result = decodeRSAPublicKey((RSAPublicKeySpec) keySpec); + else if (keySpec instanceof DHPublicKeySpec) + result = decodeDHPublicKey((DHPublicKeySpec) keySpec); + else + { + if (! (keySpec instanceof X509EncodedKeySpec)) + throw new InvalidKeySpecException("Unsupported key specification"); + + byte[] input = ((X509EncodedKeySpec) keySpec).getEncoded(); + boolean ok = false; + // try DSS + try + { + result = DSSPublicKey.valueOf(input); + ok = true; + } + catch (InvalidParameterException ignored) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception in DSSPublicKey.valueOf(). Ignore", + ignored); + } + if (! ok) // try RSA + try + { + result = GnuRSAPublicKey.valueOf(input); + ok = true; + } + catch (InvalidParameterException ignored) + { + if (Configuration.DEBUG) + log.log(Level.FINE, + "Exception in GnuRSAPublicKey.valueOf(). Ignore", + ignored); + } + if (! ok) // try DH + result = decodeDHPublicKey(input); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGeneratePublic()", result); + return result; + } + + protected PrivateKey engineGeneratePrivate(KeySpec keySpec) + throws InvalidKeySpecException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineGeneratePrivate()", keySpec); + PrivateKey result = null; + if (keySpec instanceof DSAPrivateKeySpec) + result = decodeDSSPrivateKey((DSAPrivateKeySpec) keySpec); + else if (keySpec instanceof RSAPrivateCrtKeySpec) + result = decodeRSAPrivateKey((RSAPrivateCrtKeySpec) keySpec); + else if (keySpec instanceof DHPrivateKeySpec) + result = decodeDHPrivateKey((DHPrivateKeySpec) keySpec); + else + { + if (! (keySpec instanceof PKCS8EncodedKeySpec)) + throw new InvalidKeySpecException("Unsupported key specification"); + + byte[] input = ((PKCS8EncodedKeySpec) keySpec).getEncoded(); + boolean ok = false; + // try DSS + try + { + result = DSSPrivateKey.valueOf(input); + ok = true; + } + catch (InvalidParameterException ignored) + { + if (Configuration.DEBUG) + log.log(Level.FINE, "Exception in DSSPrivateKey.valueOf(). Ignore", + ignored); + } + if (! ok) // try RSA + try + { + result = GnuRSAPrivateKey.valueOf(input); + ok = true; + } + catch (InvalidParameterException ignored) + { + if (Configuration.DEBUG) + log.log(Level.FINE, + "Exception in GnuRSAPrivateKey.valueOf(). Ignore", + ignored); + } + if (! ok) // try DH + result = decodeDHPrivateKey(input); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineGeneratePrivate()", result); + return result; + } + + protected KeySpec engineGetKeySpec(Key key, Class keySpec) + throws InvalidKeySpecException + { + if (key instanceof PublicKey + && Registry.X509_ENCODING_SORT_NAME.equalsIgnoreCase(key.getFormat()) + && keySpec.isAssignableFrom(X509EncodedKeySpec.class)) + return new X509EncodedKeySpec(key.getEncoded()); + + if (key instanceof PrivateKey + && Registry.PKCS8_ENCODING_SHORT_NAME.equalsIgnoreCase(key.getFormat()) + && keySpec.isAssignableFrom(PKCS8EncodedKeySpec.class)) + return new PKCS8EncodedKeySpec(key.getEncoded()); + + throw new InvalidKeySpecException("Unsupported format or invalid key spec class"); + } + + protected Key engineTranslateKey(Key key) throws InvalidKeyException + { + throw new InvalidKeyException("Key translation not supported"); + } + + /** + * @param spec an instance of {@link DSAPublicKeySpec} to decode. + * @return an instance of {@link DSSPublicKey} constructed from the + * information in the designated key-specification. + */ + private DSSPublicKey decodeDSSPublicKey(DSAPublicKeySpec spec) + { + BigInteger p = spec.getP(); + BigInteger q = spec.getQ(); + BigInteger g = spec.getG(); + BigInteger y = spec.getY(); + return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y); + } + + /** + * @param spec an instance of {@link RSAPublicKeySpec} to decode. + * @return an instance of {@link GnuRSAPublicKey} constructed from the + * information in the designated key-specification. + */ + private GnuRSAPublicKey decodeRSAPublicKey(RSAPublicKeySpec spec) + { + BigInteger n = spec.getModulus(); + BigInteger e = spec.getPublicExponent(); + return new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e); + } + + /** + * @param spec an instance of {@link DHPublicKeySpec} to decode. + * @return an instance of a {@link DHPublicKey} constructed from the + * information in the designated key-specification. + * @throws InvalidKeySpecException if no concrete implementation of the + * {@link DHPublicKey} interface exists at run-time, or if an + * exception occurs during its instantiation. + */ + private DHPublicKey decodeDHPublicKey(DHPublicKeySpec spec) + throws InvalidKeySpecException + { + BigInteger p = spec.getP(); + BigInteger g = spec.getG(); + BigInteger y = spec.getY(); + Object[] params = new Object[] {Integer.valueOf(Registry.X509_ENCODING_ID), + null, p, g, y}; + Object obj = invokeConstructor("gnu.javax.crypto.key.dh.GnuDHPublicKey", + params); + return (DHPublicKey) obj; + } + + /** + * @param encoded the bytes to decode. + * @return an instance of a {@link DHPublicKey} constructed from the + * information in the designated key-specification. + * @throws InvalidKeySpecException if no concrete implementation of the + * {@link DHPublicKey} interface exists at run-time, or if an + * exception occurs during its instantiation. + */ + private DHPublicKey decodeDHPublicKey(byte[] encoded) + throws InvalidKeySpecException + { + Object obj = invokeValueOf("gnu.javax.crypto.key.dh.GnuDHPublicKey", + encoded); + return (DHPublicKey) obj; + } + + /** + * @param spec an instance of {@link DSAPrivateKeySpec} to decode. + * @return an instance of {@link DSSPrivateKey} constructed from the + * information in the designated key-specification. + */ + private PrivateKey decodeDSSPrivateKey(DSAPrivateKeySpec spec) + { + BigInteger p = spec.getP(); + BigInteger q = spec.getQ(); + BigInteger g = spec.getG(); + BigInteger x = spec.getX(); + return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x); + } + + /** + * @param spec an instance of {@link RSAPrivateCrtKeySpec} to decode. + * @return an instance of {@link GnuRSAPrivateKey} constructed from the + * information in the designated key-specification. + */ + private PrivateKey decodeRSAPrivateKey(RSAPrivateCrtKeySpec spec) + { + BigInteger n = spec.getModulus(); + BigInteger e = spec.getPublicExponent(); + BigInteger d = spec.getPrivateExponent(); + BigInteger p = spec.getPrimeP(); + BigInteger q = spec.getPrimeQ(); + BigInteger dP = spec.getPrimeExponentP(); + BigInteger dQ = spec.getPrimeExponentQ(); + BigInteger qInv = spec.getCrtCoefficient(); + return new GnuRSAPrivateKey(Registry.PKCS8_ENCODING_ID, + n, e, d, p, q, dP, dQ, qInv); + } + + /** + * @param spec an instance of {@link DHPrivateKeySpec} to decode. + * @return an instance of a {@link DHPrivateKey} constructed from the + * information in the designated key-specification. + * @throws InvalidKeySpecException if no concrete implementation of the + * {@link DHPrivateKey} interface exists at run-time, or if an + * exception occurs during its instantiation. + */ + private DHPrivateKey decodeDHPrivateKey(DHPrivateKeySpec spec) + throws InvalidKeySpecException + { + BigInteger p = spec.getP(); + BigInteger g = spec.getG(); + BigInteger x = spec.getX(); + Object[] params = new Object[] {Integer.valueOf(Registry.PKCS8_ENCODING_ID), + null, p, g, x}; + Object obj = invokeConstructor("gnu.javax.crypto.key.dh.GnuDHPrivateKey", + params); + return (DHPrivateKey) obj; + } + + /** + * @param encoded the bytes to decode. + * @return an instance of a {@link DHPrivateKey} constructed from the + * information in the designated key-specification. + * @throws InvalidKeySpecException if no concrete implementation of the + * {@link DHPrivateKey} interface exists at run-time, or if an + * exception occurs during its instantiation. + */ + private DHPrivateKey decodeDHPrivateKey(byte[] encoded) + throws InvalidKeySpecException + { + Object obj = invokeValueOf("gnu.javax.crypto.key.dh.GnuDHPrivateKey", + encoded); + return (DHPrivateKey) obj; + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java b/libjava/classpath/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java new file mode 100644 index 000000000..9d3e5efdd --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/KeyPairGeneratorAdapter.java @@ -0,0 +1,95 @@ +/* KeyPairGeneratorAdapter.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.key.KeyPairGeneratorFactory; + +import java.security.InvalidAlgorithmParameterException; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.SecureRandom; +import java.security.spec.AlgorithmParameterSpec; + +/** + * The implementation of a generic {@link java.security.KeyPairGenerator} + * adapter class to wrap GNU keypair generator instances. + *

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

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

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

+ * In case the client does not explicitly initialize the KeyPairGenerator (via a + * call to an initialize() method), the GNU provider uses a + * default modulus size (keysize) of 1024 bits. + */ +public class RSAKeyPairGeneratorSpi + extends KeyPairGeneratorAdapter +{ + public RSAKeyPairGeneratorSpi() + { + super(Registry.RSA_KPG); + } + + public void initialize(int keysize, SecureRandom random) + { + HashMap attributes = new HashMap(); + attributes.put(RSAKeyPairGenerator.MODULUS_LENGTH, Integer.valueOf(keysize)); + if (random != null) + attributes.put(RSAKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + + attributes.put(RSAKeyPairGenerator.PREFERRED_ENCODING_FORMAT, + Integer.valueOf(Registry.ASN1_ENCODING_ID)); + adaptee.setup(attributes); + } + + public void initialize(AlgorithmParameterSpec params, SecureRandom random) + throws InvalidAlgorithmParameterException + { + HashMap attributes = new HashMap(); + if (params != null) + { + if (! (params instanceof RSAKeyGenParameterSpec)) + throw new InvalidAlgorithmParameterException("params"); + + attributes.put(RSAKeyPairGenerator.RSA_PARAMETERS, params); + } + if (random != null) + attributes.put(RSAKeyPairGenerator.SOURCE_OF_RANDOMNESS, random); + + attributes.put(RSAKeyPairGenerator.PREFERRED_ENCODING_FORMAT, + Integer.valueOf(Registry.ASN1_ENCODING_ID)); + adaptee.setup(attributes); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java b/libjava/classpath/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java new file mode 100644 index 000000000..496c9caa6 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/RSAPSSRawSignatureSpi.java @@ -0,0 +1,56 @@ +/* RSAPSSRawSignatureSpi.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.RSAPSSSignatureRawCodec; + +/** + * The implementation of Service Provider Interface (SPI) + * adapter for the RSA-PSS signature scheme, encoded and/or decoded in RAW + * format. + */ +public class RSAPSSRawSignatureSpi + extends SignatureAdapter +{ + public RSAPSSRawSignatureSpi() + { + super(Registry.RSA_PSS_SIG, new RSAPSSSignatureRawCodec()); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/SHA160withDSS.java b/libjava/classpath/gnu/java/security/jce/sig/SHA160withDSS.java new file mode 100644 index 000000000..c55139f46 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/SHA160withDSS.java @@ -0,0 +1,54 @@ +/* SHA160withDSS.java -- JCE Adapter for DSS with SHA1 signatures + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.dss.DSSSignatureX509Codec; + +/** + * A JCE Adapter for providing X.509 formatted DSS with SHA1 signatures. + */ +public class SHA160withDSS + extends SignatureAdapter +{ + public SHA160withDSS() + { + super(Registry.DSS_SIG, new DSSSignatureX509Codec()); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/SHA160withRSA.java b/libjava/classpath/gnu/java/security/jce/sig/SHA160withRSA.java new file mode 100644 index 000000000..d3b2054e0 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/SHA160withRSA.java @@ -0,0 +1,56 @@ +/* SHA160withRSA.java -- RSA PKCS1 with SHA160 JCE signature Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; + +/** + * A JCE Adapter for the RSA PKCS1 (v1.5) signature with SHA160 hash and X.509 + * encoding format. + */ +public class SHA160withRSA + extends SignatureAdapter +{ + public SHA160withRSA() + { + super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA160_HASH, + new RSAPKCS1V1_5SignatureX509Codec()); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/SHA256withRSA.java b/libjava/classpath/gnu/java/security/jce/sig/SHA256withRSA.java new file mode 100644 index 000000000..d21888b59 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/SHA256withRSA.java @@ -0,0 +1,56 @@ +/* SHA256withRSA.java -- RSA PKCS1 with SHA256 JCE signature Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; + +/** + * A JCE Adapter for the RSA PKCS1 (v1.5) signature with SHA256 hash and X.509 + * encoding format. + */ +public class SHA256withRSA + extends SignatureAdapter +{ + public SHA256withRSA() + { + super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA256_HASH, + new RSAPKCS1V1_5SignatureX509Codec()); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/SHA384withRSA.java b/libjava/classpath/gnu/java/security/jce/sig/SHA384withRSA.java new file mode 100644 index 000000000..5495ec1ca --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/SHA384withRSA.java @@ -0,0 +1,56 @@ +/* SHA384withRSA.java -- RSA PKCS1 with SHA384 JCE signature Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; + +/** + * A JCE Adapter for the RSA PKCS1 (v1.5) signature with SHA384 hash and X.509 + * encoding format. + */ +public class SHA384withRSA + extends SignatureAdapter +{ + public SHA384withRSA() + { + super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA384_HASH, + new RSAPKCS1V1_5SignatureX509Codec()); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/SHA512withRSA.java b/libjava/classpath/gnu/java/security/jce/sig/SHA512withRSA.java new file mode 100644 index 000000000..f7632290a --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/SHA512withRSA.java @@ -0,0 +1,56 @@ +/* SHA512withRSA.java -- RSA PKCS1 with SHA512 JCE signature Adapter + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Registry; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; + +/** + * A JCE Adapter for the RSA PKCS1 (v1.5) signature with SHA512 hash and X.509 + * encoding format. + */ +public class SHA512withRSA + extends SignatureAdapter +{ + public SHA512withRSA() + { + super(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA512_HASH, + new RSAPKCS1V1_5SignatureX509Codec()); + } +} diff --git a/libjava/classpath/gnu/java/security/jce/sig/SignatureAdapter.java b/libjava/classpath/gnu/java/security/jce/sig/SignatureAdapter.java new file mode 100644 index 000000000..0ed1e2f41 --- /dev/null +++ b/libjava/classpath/gnu/java/security/jce/sig/SignatureAdapter.java @@ -0,0 +1,250 @@ +/* SignatureAdapter.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.jce.sig; + +import gnu.java.security.Configuration; +import gnu.java.security.sig.BaseSignature; +import gnu.java.security.sig.ISignature; +import gnu.java.security.sig.ISignatureCodec; +import gnu.java.security.sig.SignatureFactory; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.SignatureException; +import java.security.SignatureSpi; +import java.security.spec.AlgorithmParameterSpec; +import java.util.HashMap; +import java.util.logging.Logger; + +/** + * The implementation of a generic {@link java.security.Signature} adapter class + * to wrap GNU signature instances. + *

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

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

+ * All the implementations which subclass this object, and which are serviced by + * the GNU provider implement the {@link Cloneable} interface. + */ +class SignatureAdapter + extends SignatureSpi + implements Cloneable +{ + private static final Logger log = Logger.getLogger(SignatureAdapter.class.getName()); + + /** Our underlying signature instance. */ + private ISignature adaptee; + + /** Our underlying signature encoder/decoder engine. */ + private ISignatureCodec codec; + + /** + * Trivial protected constructor. + * + * @param sigName the canonical name of the signature scheme. + * @param codec the signature codec engine to use with this scheme. + */ + protected SignatureAdapter(String sigName, ISignatureCodec codec) + { + this(SignatureFactory.getInstance(sigName), codec); + } + + /** + * Private constructor for cloning purposes. + * + * @param adaptee a clone of the underlying signature scheme instance. + * @param codec the signature codec engine to use with this scheme. + */ + private SignatureAdapter(ISignature adaptee, ISignatureCodec codec) + { + super(); + + this.adaptee = adaptee; + this.codec = codec; + } + + public Object clone() + { + return new SignatureAdapter((ISignature) adaptee.clone(), codec); + } + + public void engineInitVerify(PublicKey publicKey) throws InvalidKeyException + { + HashMap attributes = new HashMap(); + attributes.put(BaseSignature.VERIFIER_KEY, publicKey); + try + { + adaptee.setupVerify(attributes); + } + catch (IllegalArgumentException x) + { + throw new InvalidKeyException(x.getMessage(), x); + } + } + + public void engineInitSign(PrivateKey privateKey) throws InvalidKeyException + { + HashMap attributes = new HashMap(); + attributes.put(BaseSignature.SIGNER_KEY, privateKey); + try + { + adaptee.setupSign(attributes); + } + catch (IllegalArgumentException x) + { + throw new InvalidKeyException(x.getMessage(), x); + } + } + + public void engineInitSign(PrivateKey privateKey, SecureRandom random) + throws InvalidKeyException + { + HashMap attributes = new HashMap(); + attributes.put(BaseSignature.SIGNER_KEY, privateKey); + attributes.put(BaseSignature.SOURCE_OF_RANDOMNESS, random); + try + { + adaptee.setupSign(attributes); + } + catch (IllegalArgumentException x) + { + throw new InvalidKeyException(x.getMessage(), x); + } + } + + public void engineUpdate(byte b) throws SignatureException + { + try + { + adaptee.update(b); + } + catch (IllegalStateException x) + { + throw new SignatureException(x.getMessage(), x); + } + } + + public void engineUpdate(byte[] b, int off, int len) + throws SignatureException + { + try + { + adaptee.update(b, off, len); + } + catch (IllegalStateException x) + { + throw new SignatureException(x.getMessage(), x); + } + } + + public byte[] engineSign() throws SignatureException + { + Object signature = null; + try + { + signature = adaptee.sign(); + } + catch (IllegalStateException x) + { + throw new SignatureException(x.getMessage(), x); + } + byte[] result = codec.encodeSignature(signature); + return result; + } + + public int engineSign(byte[] outbuf, int offset, int len) + throws SignatureException + { + byte[] signature = this.engineSign(); + int result = signature.length; + if (result > len) + throw new SignatureException("Not enough room to store signature"); + + System.arraycopy(signature, 0, outbuf, offset, result); + return result; + } + + public boolean engineVerify(byte[] sigBytes) throws SignatureException + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "engineVerify"); + Object signature = codec.decodeSignature(sigBytes); + boolean result = false; + try + { + result = adaptee.verify(signature); + } + catch (IllegalStateException x) + { + throw new SignatureException(x.getMessage(), x); + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "engineVerify", + Boolean.valueOf(result)); + return result; + } + + // Deprecated. Replaced by engineSetParameter. + public void engineSetParameter(String param, Object value) + throws InvalidParameterException + { + throw new InvalidParameterException("deprecated"); + } + + public void engineSetParameter(AlgorithmParameterSpec params) + throws InvalidAlgorithmParameterException + { + } + + // Deprecated + public Object engineGetParameter(String param) + throws InvalidParameterException + { + throw new InvalidParameterException("deprecated"); + } +} diff --git a/libjava/classpath/gnu/java/security/key/IKeyPairCodec.java b/libjava/classpath/gnu/java/security/key/IKeyPairCodec.java new file mode 100644 index 000000000..5c88c86ca --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/IKeyPairCodec.java @@ -0,0 +1,124 @@ +/* IKeyPairCodec.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key; + +import gnu.java.security.Registry; + +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * The visible methods of an object that knows how to encode and decode + * cryptographic asymmetric keypairs. Codecs are useful for (a) externalising + * public and private keys for storage and on-the-wire transmission, as well as + * (b) re-creating their internal Java representation from external sources. + */ +public interface IKeyPairCodec +{ + /** Constant identifying the Raw encoding format. */ + int RAW_FORMAT = Registry.RAW_ENCODING_ID; + + /** Constant identifying the X.509 encoding format. */ + int X509_FORMAT = Registry.X509_ENCODING_ID; + + /** Constant identifying the PKCS#8 encoding format. */ + int PKCS8_FORMAT = Registry.PKCS8_ENCODING_ID; + + /** + * Constant identifying the ASN.1 encoding format: a combined encoding + * of X.509 for public keys, and PKCS#8 for private ones. + */ + int ASN1_FORMAT = Registry.ASN1_ENCODING_ID; + + /** + * Returns the unique identifier (within this library) of the format used to + * externalise public and private keys. + * + * @return the identifier of the format, the object supports. + */ + int getFormatID(); + + /** + * Encodes an instance of a public key for storage or transmission purposes. + * + * @param key the non-null key to encode. + * @return a byte sequence representing the encoding of the designated key + * according to the format supported by this codec. + * @exception IllegalArgumentException if the designated key is not supported + * by this codec. + */ + byte[] encodePublicKey(PublicKey key); + + /** + * Encodes an instance of a private key for storage or transmission purposes. + * + * @param key the non-null key to encode. + * @return a byte sequence representing the encoding of the designated key + * according to the format supported by this codec. + * @exception IllegalArgumentException if the designated key is not supported + * by this codec. + */ + byte[] encodePrivateKey(PrivateKey key); + + /** + * Decodes an instance of an external public key into its native Java + * representation. + * + * @param input the source of the externalised key to decode. + * @return a concrete instance of a public key, reconstructed from the + * designated input. + * @exception IllegalArgumentException if the designated input does not + * contain a known representation of a public key for the format + * supported by the concrete codec. + */ + PublicKey decodePublicKey(byte[] input); + + /** + * Decodes an instance of an external private key into its native Java + * representation. + * + * @param input the source of the externalised key to decode. + * @return a concrete instance of a private key, reconstructed from the + * designated input. + * @exception IllegalArgumentException if the designated input does not + * contain a known representation of a private key for the format + * supported by the concrete codec. + */ + PrivateKey decodePrivateKey(byte[] input); +} diff --git a/libjava/classpath/gnu/java/security/key/IKeyPairGenerator.java b/libjava/classpath/gnu/java/security/key/IKeyPairGenerator.java new file mode 100644 index 000000000..72aac2463 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/IKeyPairGenerator.java @@ -0,0 +1,73 @@ +/* IKeyPairGenerator.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key; + +import java.security.KeyPair; +import java.util.Map; + +/** + * The visible methods of every asymmetric keypair generator. + */ +public interface IKeyPairGenerator +{ + /** + * Returns the canonical name of this keypair generator. + * + * @return the canonical name of this instance. + */ + String name(); + + /** + * [Re]-initialises this instance for use with a given set of attributes. + * + * @param attributes a map of name/value pairs to use for setting up the + * instance. + * @exception IllegalArgumentException if at least one of the mandatory + * attributes is missing or an invalid value was specified. + */ + void setup(Map attributes); + + /** + * Generates a new keypair based on the attributes used to configure the + * instance. + * + * @return a new keypair. + */ + KeyPair generate(); +} diff --git a/libjava/classpath/gnu/java/security/key/KeyPairCodecFactory.java b/libjava/classpath/gnu/java/security/key/KeyPairCodecFactory.java new file mode 100644 index 000000000..d42866423 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/KeyPairCodecFactory.java @@ -0,0 +1,360 @@ +/* KeyPairCodecFactory.java -- + Copyright 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key; + +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSKeyPairPKCS8Codec; +import gnu.java.security.key.dss.DSSKeyPairRawCodec; +import gnu.java.security.key.dss.DSSKeyPairX509Codec; +import gnu.java.security.key.dss.DSSPrivateKey; +import gnu.java.security.key.dss.DSSPublicKey; +import gnu.java.security.key.rsa.GnuRSAPrivateKey; +import gnu.java.security.key.rsa.GnuRSAPublicKey; +import gnu.java.security.key.rsa.RSAKeyPairPKCS8Codec; +import gnu.java.security.key.rsa.RSAKeyPairRawCodec; +import gnu.java.security.key.rsa.RSAKeyPairX509Codec; +import gnu.java.security.util.FormatUtil; + +import java.lang.reflect.Constructor; +import java.security.Key; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory class to instantiate key encoder/decoder instances. + */ +public class KeyPairCodecFactory +{ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private KeyPairCodecFactory() + { + super(); + } + + /** + * Returns the appropriate codec given a composed key-pair generator algorithm + * and an encoding format. A composed name is formed by the concatenation of + * the canonical key-pair algorithm name, the forward slash character + * / and the canonical name of the encoding format. + *

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

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

+ * IMPORTANT: Under certain circumstances (e.g. in an X.509 certificate + * with inherited AlgorithmIdentifier's parameters of a SubjectPublicKeyInfo + * element) these three MPIs may be null. + * + * @see DSSPrivateKey#getEncoded + * @see DSSPublicKey#getEncoded + */ +public abstract class DSSKey + implements Key, DSAKey +{ + /** + * A prime modulus, where + * 2L-1 < p < 2L for + * 512 <= L <= 1024 and L a multiple of + * 64. + */ + protected final BigInteger p; + + /** + * A prime divisor of p - 1, where + * 2159 < q + * < 2160. + */ + protected final BigInteger q; + + /** + * g = h(p-1)/q mod p, where h is + * any integer with 1 < h < p - 1 such that h + * (p-1)/q mod p > 1 (g + * has order q mod p + * ). + */ + protected final BigInteger g; + + /** + * Identifier of the default encoding format to use when externalizing the key + * material. + */ + protected final int defaultFormat; + + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Trivial protected constructor. + * + * @param defaultFormat the identifier of the encoding format to use by + * default when externalizing the key. + * @param p the DSS parameter p. + * @param q the DSS parameter q. + * @param g the DSS parameter g. + */ + protected DSSKey(int defaultFormat, BigInteger p, BigInteger q, BigInteger g) + { + super(); + + this.defaultFormat = defaultFormat <= 0 ? Registry.RAW_ENCODING_ID + : defaultFormat; + this.p = p; + this.q = q; + this.g = g; + } + + public DSAParams getParams() + { + return new DSAParameterSpec(p, q, g); + } + + public String getAlgorithm() + { + return Registry.DSS_KPG; + } + + /** @deprecated see getEncoded(int). */ + public byte[] getEncoded() + { + return getEncoded(defaultFormat); + } + + public String getFormat() + { + return FormatUtil.getEncodingShortName(defaultFormat); + } + + /** + * Returns true if the designated object is an instance of + * {@link DSAKey} and has the same DSS (Digital Signature Standard) parameter + * values as this one. + *

+ * Always returns false if the MPIs of this key are + * inherited. This may be the case when the key is re-constructed from + * an X.509 certificate with absent or NULL AlgorithmIdentifier's parameters + * field. + * + * @param obj the other non-null DSS key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (hasInheritedParameters()) + return false; + + if (obj == null) + return false; + + if (! (obj instanceof DSAKey)) + return false; + + DSAKey that = (DSAKey) obj; + return p.equals(that.getParams().getP()) + && q.equals(that.getParams().getQ()) + && g.equals(that.getParams().getG()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged(new GetPropertyAction("line.separator")); + CPStringBuilder sb = new CPStringBuilder(ls) + .append("defaultFormat=").append(defaultFormat).append(",") + .append(ls); + if (hasInheritedParameters()) + sb.append("p=inherited,").append(ls) + .append("q=inherited,").append(ls) + .append("g=inherited"); + else + sb.append("p=0x").append(p.toString(16)).append(",").append(ls) + .append("q=0x").append(q.toString(16)).append(",").append(ls) + .append("g=0x").append(g.toString(16)); + str = sb.toString(); + } + return str; + } + + public abstract byte[] getEncoded(int format); + + /** + * @return true if p, q and + * g are all null. Returns + * false otherwise. + */ + public boolean hasInheritedParameters() + { + return p == null && q == null && g == null; + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java new file mode 100644 index 000000000..6bda4e88e --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairGenerator.java @@ -0,0 +1,382 @@ +/* DSSKeyPairGenerator.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.hash.Sha160; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.DSAParameterSpec; +import java.util.Map; +import java.util.logging.Logger; + +/** + * A key-pair generator for asymetric keys to use in conjunction with the DSS + * (Digital Signature Standard). + *

+ * References: + *

+ * Digital Signature + * Standard (DSS), Federal Information Processing Standards Publication + * 186. National Institute of Standards and Technology. + */ +public class DSSKeyPairGenerator + implements IKeyPairGenerator +{ + private static final Logger log = Logger.getLogger(DSSKeyPairGenerator.class.getName()); + + /** The BigInteger constant 2. */ + private static final BigInteger TWO = BigInteger.valueOf(2L); + + /** Property name of the length (Integer) of the modulus (p) of a DSS key. */ + public static final String MODULUS_LENGTH = "gnu.crypto.dss.L"; + + /** + * Property name of the Boolean indicating wether or not to use default pre- + * computed values of p, q and g + * for a given modulus length. The ultimate behaviour of this generator with + * regard to using pre-computed parameter sets will depend on the value of + * this property and of the following one {@link #STRICT_DEFAULTS}: + *

    + *
  1. If this property is {@link Boolean#FALSE} then this generator will + * accept being setup for generating parameters for any modulus length + * provided the modulus length is between 512 and + * 1024, and is of the form 512 + 64 * n. In + * addition, a new paramter set will always be generated; i.e. no pre- + * computed values are used.
  2. + *
  3. If this property is {@link Boolean#TRUE} and the value of + * {@link #STRICT_DEFAULTS} is also {@link Boolean#TRUE} then this generator + * will only accept being setup for generating parameters for modulus lengths + * of 512, 768 and 1024. Any + * other value, of the modulus length, even if between 512 and + * 1024, and of the form 512 + 64 * n, will + * cause an {@link IllegalArgumentException} to be thrown. When those modulus + * length (512, 768, and 1024) + * are specified, the paramter set is always the same.
  4. + *
  5. Finally, if this property is {@link Boolean#TRUE} and the value of + * {@link #STRICT_DEFAULTS} is {@link Boolean#FALSE} then this generator will + * behave as in point 1 above, except that it will use pre-computed values + * when possible; i.e. the modulus length is one of 512, + * 768, or 1024.
  6. + *
+ * The default value of this property is {@link Boolean#TRUE}. + */ + public static final String USE_DEFAULTS = "gnu.crypto.dss.use.defaults"; + + /** + * Property name of the Boolean indicating wether or not to generate new + * parameters, even if the modulus length L is not one of the pre- + * computed defaults (value {@link Boolean#FALSE}), or throw an exception + * (value {@link Boolean#TRUE}) -- the exception in this case is an + * {@link IllegalArgumentException}. The default value for this property is + * {@link Boolean#FALSE}. The ultimate behaviour of this generator will + * depend on the values of this and {@link #USE_DEFAULTS} properties -- see + * {@link #USE_DEFAULTS} for more information. + */ + public static final String STRICT_DEFAULTS = "gnu.crypto.dss.strict.defaults"; + + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a classloader singleton from {@link PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.dss.prng"; + + /** + * Property name of an optional {@link DSAParameterSpec} instance to use for + * this generator's p, q, and g + * values. The default is to generate these values or use pre-computed ones, + * depending on the value of the USE_DEFAULTS attribute. + */ + public static final String DSS_PARAMETERS = "gnu.crypto.dss.params"; + + /** + * Property name of the preferred encoding format to use when externalizing + * generated instance of key-pairs from this generator. The property is taken + * to be an {@link Integer} that encapsulates an encoding format identifier. + */ + public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.dss.encoding"; + + /** Default value for the modulus length. */ + public static final int DEFAULT_MODULUS_LENGTH = 1024; + + /** Default encoding format to use when none was specified. */ + private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID; + + /** Initial SHS context. */ + private static final int[] T_SHS = new int[] { + 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0 + }; + + // from jdk1.3.1/docs/guide/security/CryptoSpec.html#AppB + public static final DSAParameterSpec KEY_PARAMS_512 = new DSAParameterSpec( + new BigInteger( + "fca682ce8e12caba26efccf7110e526db078b05edecbcd1eb4a208f3ae1617ae" + + "01f35b91a47e6df63413c5e12ed0899bcd132acd50d99151bdc43ee737592e17", 16), + new BigInteger("962eddcc369cba8ebb260ee6b6a126d9346e38c5", 16), + new BigInteger( + "678471b27a9cf44ee91a49c5147db1a9aaf244f05a434d6486931d2d14271b9e" + + "35030b71fd73da179069b32e2935630e1c2062354d0da20a6c416e50be794ca4", 16)); + public static final DSAParameterSpec KEY_PARAMS_768 = new DSAParameterSpec( + new BigInteger( + "e9e642599d355f37c97ffd3567120b8e25c9cd43e927b3a9670fbec5d8901419" + + "22d2c3b3ad2480093799869d1e846aab49fab0ad26d2ce6a22219d470bce7d77" + + "7d4a21fbe9c270b57f607002f3cef8393694cf45ee3688c11a8c56ab127a3daf", 16), + new BigInteger("9cdbd84c9f1ac2f38d0f80f42ab952e7338bf511", 16), + new BigInteger( + "30470ad5a005fb14ce2d9dcd87e38bc7d1b1c5facbaecbe95f190aa7a31d23c4" + + "dbbcbe06174544401a5b2c020965d8c2bd2171d3668445771f74ba084d2029d8" + + "3c1c158547f3a9f1a2715be23d51ae4d3e5a1f6a7064f316933a346d3f529252", 16)); + public static final DSAParameterSpec KEY_PARAMS_1024 = new DSAParameterSpec( + new BigInteger( + "fd7f53811d75122952df4a9c2eece4e7f611b7523cef4400c31e3f80b6512669" + + "455d402251fb593d8d58fabfc5f5ba30f6cb9b556cd7813b801d346ff26660b7" + + "6b9950a5a49f9fe8047b1022c24fbba9d7feb7c61bf83b57e7c6a8a6150f04fb" + + "83f6d3c51ec3023554135a169132f675f3ae2b61d72aeff22203199dd14801c7", 16), + new BigInteger("9760508f15230bccb292b982a2eb840bf0581cf5", 16), + new BigInteger( + "f7e1a085d69b3ddecbbcab5c36b857b97994afbbfa3aea82f9574c0b3d078267" + + "5159578ebad4594fe67107108180b449167123e84c281613b7cf09328cc8a6e1" + + "3c167a8b547c8d28e0a3ae1e2bb3a675916ea37f0bfa213562f1fb627a01243b" + + "cca4f1bea8519089a883dfe15ae59f06928b665e807b552564014c3bfecf492a", 16)); + + private static final BigInteger TWO_POW_160 = TWO.pow(160); + + /** The length of the modulus of DSS keys generated by this instance. */ + private int L; + + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + + private BigInteger seed; + + private BigInteger counter; + + private BigInteger p; + + private BigInteger q; + + private BigInteger e; + + private BigInteger g; + + private BigInteger XKEY; + + /** Our default source of randomness. */ + private PRNG prng = null; + + /** Preferred encoding format of generated keys. */ + private int preferredFormat; + + public String name() + { + return Registry.DSS_KPG; + } + + /** + * Configures this instance. + * + * @param attributes the map of name/value pairs to use. + * @exception IllegalArgumentException if the designated MODULUS_LENGTH value + * is not greater than 512, less than 1024 and not of the form + * 512 + 64j. + */ + public void setup(Map attributes) + { + // find out the modulus length + Integer l = (Integer) attributes.get(MODULUS_LENGTH); + L = (l == null ? DEFAULT_MODULUS_LENGTH : l.intValue()); + if ((L % 64) != 0 || L < 512 || L > 1024) + throw new IllegalArgumentException(MODULUS_LENGTH); + + // should we use the default pre-computed params? + Boolean useDefaults = (Boolean) attributes.get(USE_DEFAULTS); + if (useDefaults == null) + useDefaults = Boolean.TRUE; + + Boolean strictDefaults = (Boolean) attributes.get(STRICT_DEFAULTS); + if (strictDefaults == null) + strictDefaults = Boolean.FALSE; + + // are we given a set of DSA params or we shall use/generate our own? + DSAParameterSpec params = (DSAParameterSpec) attributes.get(DSS_PARAMETERS); + if (params != null) + { + p = params.getP(); + q = params.getQ(); + g = params.getG(); + } + else if (useDefaults.equals(Boolean.TRUE)) + { + switch (L) + { + case 512: + p = KEY_PARAMS_512.getP(); + q = KEY_PARAMS_512.getQ(); + g = KEY_PARAMS_512.getG(); + break; + case 768: + p = KEY_PARAMS_768.getP(); + q = KEY_PARAMS_768.getQ(); + g = KEY_PARAMS_768.getG(); + break; + case 1024: + p = KEY_PARAMS_1024.getP(); + q = KEY_PARAMS_1024.getQ(); + g = KEY_PARAMS_1024.getG(); + break; + default: + if (strictDefaults.equals(Boolean.TRUE)) + throw new IllegalArgumentException( + "Does not provide default parameters for " + L + + "-bit modulus length"); + else + { + p = null; + q = null; + g = null; + } + } + } + else + { + p = null; + q = null; + g = null; + } + // do we have a SecureRandom, or should we use our own? + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + // what is the preferred encoding format + Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT); + preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT + : formatID.intValue(); + // set the seed-key + byte[] kb = new byte[20]; // we need 160 bits of randomness + nextRandomBytes(kb); + XKEY = new BigInteger(1, kb).setBit(159).setBit(0); + } + + public KeyPair generate() + { + if (p == null) + { + BigInteger[] params = new FIPS186(L, rnd).generateParameters(); + seed = params[FIPS186.DSA_PARAMS_SEED]; + counter = params[FIPS186.DSA_PARAMS_COUNTER]; + q = params[FIPS186.DSA_PARAMS_Q]; + p = params[FIPS186.DSA_PARAMS_P]; + e = params[FIPS186.DSA_PARAMS_E]; + g = params[FIPS186.DSA_PARAMS_G]; + if (Configuration.DEBUG) + { + log.fine("seed: " + seed.toString(16)); + log.fine("counter: " + counter.intValue()); + log.fine("q: " + q.toString(16)); + log.fine("p: " + p.toString(16)); + log.fine("e: " + e.toString(16)); + log.fine("g: " + g.toString(16)); + } + } + BigInteger x = nextX(); + BigInteger y = g.modPow(x, p); + PublicKey pubK = new DSSPublicKey(preferredFormat, p, q, g, y); + PrivateKey secK = new DSSPrivateKey(preferredFormat, p, q, g, x); + return new KeyPair(pubK, secK); + } + + /** + * This method applies the following algorithm described in 3.1 of FIPS-186: + *
    + *
  1. XSEED = optional user input.
  2. + *
  3. XVAL = (XKEY + XSEED) mod 2b.
  4. + *
  5. x = G(t, XVAL) mod q.
  6. + *
  7. XKEY = (1 + XKEY + x) mod 2b.
  8. + *
+ *

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

+ * Note that in this implementation, XSEED, the optional user input, is always + * zero. + */ + private synchronized BigInteger nextX() + { + byte[] xk = XKEY.toByteArray(); + byte[] in = new byte[64]; // 512-bit block for SHS + System.arraycopy(xk, 0, in, 0, xk.length); + int[] H = Sha160.G(T_SHS[0], T_SHS[1], T_SHS[2], T_SHS[3], T_SHS[4], in, 0); + byte[] h = new byte[20]; + for (int i = 0, j = 0; i < 5; i++) + { + h[j++] = (byte)(H[i] >>> 24); + h[j++] = (byte)(H[i] >>> 16); + h[j++] = (byte)(H[i] >>> 8); + h[j++] = (byte) H[i]; + } + BigInteger result = new BigInteger(1, h).mod(q); + XKEY = XKEY.add(result).add(BigInteger.ONE).mod(TWO_POW_160); + return result; + } + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java new file mode 100644 index 000000000..a59ca3cee --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairPKCS8Codec.java @@ -0,0 +1,249 @@ +/* DSSKeyPairPKCS8Codec.java -- PKCS#8 Encoding/Decoding handler + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.Configuration; +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; +import gnu.java.security.util.Util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.logging.Logger; + +/** + * An implementation of an {@link IKeyPairCodec} that knows how to encode / + * decode PKCS#8 ASN.1 external representation of DSS private keys. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public class DSSKeyPairPKCS8Codec + implements IKeyPairCodec +{ + private static final Logger log = Logger.getLogger(DSSKeyPairPKCS8Codec.class.getName()); + private static final OID DSA_ALG_OID = new OID(Registry.DSA_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return PKCS8_FORMAT; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePublicKey(PublicKey key) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * Returns the PKCS#8 ASN.1 PrivateKeyInfo representation of a DSA + * private key. The ASN.1 specification is as follows: + * + *

+   *   PrivateKeyInfo ::= SEQUENCE {
+   *     version              INTEGER, -- MUST be 0
+   *     privateKeyAlgorithm  AlgorithmIdentifier,
+   *     privateKey           OCTET STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   *
+   *   DssParams ::= SEQUENCE {
+   *     p   INTEGER,
+   *     q   INTEGER,
+   *     g   INTEGER
+   *   }
+   * 
+ * + * @return the DER encoded form of the ASN.1 representation of the + * PrivateKeyInfo field in an X.509 certificate. + * @throw InvalidParameterException if an error occurs during the marshalling + * process. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + if (! (key instanceof DSSPrivateKey)) + throw new InvalidParameterException("Wrong key type"); + + DERValue derVersion = new DERValue(DER.INTEGER, BigInteger.ZERO); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID); + + DSSPrivateKey pk = (DSSPrivateKey) key; + BigInteger p = pk.getParams().getP(); + BigInteger q = pk.getParams().getQ(); + BigInteger g = pk.getParams().getG(); + BigInteger x = pk.getX(); + + ArrayList params = new ArrayList(3); + params.add(new DERValue(DER.INTEGER, p)); + params.add(new DERValue(DER.INTEGER, q)); + params.add(new DERValue(DER.INTEGER, g)); + DERValue derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + + ArrayList algorithmID = new ArrayList(2); + algorithmID.add(derOID); + algorithmID.add(derParams); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + // The OCTET STRING is the DER encoding of an INTEGER. + DERValue derX = new DERValue(DER.INTEGER, x); + DERValue derPrivateKey = new DERValue(DER.OCTET_STRING, derX.getEncoded()); + + ArrayList pki = new ArrayList(3); + pki.add(derVersion); + pki.add(derAlgorithmID); + pki.add(derPrivateKey); + DERValue derPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, pki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derPKI); + result = baos.toByteArray(); + } + catch (IOException e) + { + InvalidParameterException y = new InvalidParameterException(e.getMessage()); + y.initCause(e); + throw y; + } + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PublicKey decodePublicKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * @param input the byte array to unmarshall into a valid DSS + * {@link PrivateKey} instance. MUST NOT be null. + * @return a new instance of a {@link DSSPrivateKey} decoded from the + * PrivateKeyInfo material fed as input. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "decodePrivateKey"); + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger version, p, q, g, x; + DERReader der = new DERReader(input); + try + { + DERValue derPKI = der.read(); + DerUtil.checkIsConstructed(derPKI, "Wrong PrivateKeyInfo field"); + + DERValue derVersion = der.read(); + if (! (derVersion.getValue() instanceof BigInteger)) + throw new InvalidParameterException("Wrong Version field"); + + version = (BigInteger) derVersion.getValue(); + if (version.compareTo(BigInteger.ZERO) != 0) + throw new InvalidParameterException("Unexpected Version: " + version); + + DERValue derAlgoritmID = der.read(); + DerUtil.checkIsConstructed(derAlgoritmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(DSA_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + DERValue derParams = der.read(); + DerUtil.checkIsConstructed(derParams, "Wrong DSS Parameters field"); + + DERValue val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + + val = der.read(); + if (Configuration.DEBUG) + log.fine("val = " + val); + byte[] xBytes = (byte[]) val.getValue(); + if (Configuration.DEBUG) + log.fine(Util.dumpString(xBytes, "xBytes: ")); + DERReader der2 = new DERReader(xBytes); + val = der2.read(); + DerUtil.checkIsBigInteger(val, "Wrong X field"); + x = (BigInteger) val.getValue(); + } + catch (IOException e) + { + InvalidParameterException y = new InvalidParameterException(e.getMessage()); + y.initCause(e); + throw y; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "decodePrivateKey"); + return new DSSPrivateKey(Registry.PKCS8_ENCODING_ID, p, q, g, x); + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java new file mode 100644 index 000000000..5b93c6b1e --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSKeyPairRawCodec.java @@ -0,0 +1,347 @@ +/* DSSKeyPairRawCodec.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairCodec; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; + +/** + * An object that implements the {@link IKeyPairCodec} operations for the + * Raw format to use with DSS keypairs. + */ +public class DSSKeyPairRawCodec + implements IKeyPairCodec +{ + // implicit 0-arguments constructor + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * Returns the encoded form of the designated DSS (Digital Signature Standard) + * public key according to the Raw format supported by this library. + *

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

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

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

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

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

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

+   *       DSAPublicKey ::= INTEGER -- public key, Y
+   * 
+ * + * @param key the {@link PublicKey} instance to encode. MUST be an instance of + * {@link DSSPublicKey}. + * @return the ASN.1 representation of the SubjectPublicKeyInfo in an + * X.509 certificate. + * @throw InvalidParameterException if key is not an instance + * of {@link DSSPublicKey} or if an exception occurs during the + * marshalling process. + */ + public byte[] encodePublicKey(PublicKey key) + { + if (! (key instanceof DSSPublicKey)) + throw new InvalidParameterException("key"); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, DSA_ALG_OID); + + DSSPublicKey dssKey = (DSSPublicKey) key; + DERValue derParams; + if (dssKey.hasInheritedParameters()) + derParams = new DERValue(DER.NULL, null); + else + { + BigInteger p = dssKey.getParams().getP(); + BigInteger q = dssKey.getParams().getQ(); + BigInteger g = dssKey.getParams().getG(); + + DERValue derP = new DERValue(DER.INTEGER, p); + DERValue derQ = new DERValue(DER.INTEGER, q); + DERValue derG = new DERValue(DER.INTEGER, g); + + ArrayList params = new ArrayList(3); + params.add(derP); + params.add(derQ); + params.add(derG); + derParams = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, params); + } + + ArrayList algorithmID = new ArrayList(2); + algorithmID.add(derOID); + algorithmID.add(derParams); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + BigInteger y = dssKey.getY(); + DERValue derDSAPublicKey = new DERValue(DER.INTEGER, y); + byte[] yBytes = derDSAPublicKey.getEncoded(); + DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(yBytes)); + + ArrayList spki = new ArrayList(2); + spki.add(derAlgorithmID); + spki.add(derSPK); + DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derSPKI); + result = baos.toByteArray(); + } + catch (IOException x) + { + InvalidParameterException e = new InvalidParameterException(x.getMessage()); + e.initCause(x); + throw e; + } + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + throw new InvalidParameterException("Wrong format for private keys"); + } + + /** + * @param input the byte array to unmarshall into a valid DSS + * {@link PublicKey} instance. MUST NOT be null. + * @return a new instance of a {@link DSSPublicKey} decoded from the + * SubjectPublicKeyInfo material in an X.509 certificate. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PublicKey decodePublicKey(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger p = null; + BigInteger g = null; + BigInteger q = null; + BigInteger y; + DERReader der = new DERReader(input); + try + { + DERValue derSPKI = der.read(); + DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field"); + + DERValue derAlgorithmID = der.read(); + DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + if (! (derOID.getValue() instanceof OID)) + throw new InvalidParameterException("Wrong Algorithm field"); + + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(DSA_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + DERValue val = der.read(); + // RFC-3280, page 79 states: "If the subjectPublicKeyInfo field of the + // certificate contains an algorithm field with null parameters or + // parameters are omitted, compare the certificate subjectPublicKey + // algorithm to the working_public_key_algorithm. If the certificate + // subjectPublicKey algorithm and the working_public_key_algorithm are + // different, set the working_public_key_parameters to null." + // in other words, the parameters field of an AlgorithmIdentifier + // element MAY NOT be present at all, or if present MAY be NULL! + // the Mauve test ValidDSAParameterInheritenceTest5, in + // gnu.testlet.java.security.cert.pkix.pkits, is/was failing because + // of this. + if (val.getTag() == DER.NULL) + val = der.read(); + else if (val.isConstructed()) + { + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong P field"); + p = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong Q field"); + q = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong G field"); + g = (BigInteger) val.getValue(); + + val = der.read(); + } + + if (! (val.getValue() instanceof BitString)) + throw new InvalidParameterException("Wrong SubjectPublicKey field"); + + byte[] yBytes = ((BitString) val.getValue()).toByteArray(); + + DERReader dsaPub = new DERReader(yBytes); + val = dsaPub.read(); + DerUtil.checkIsBigInteger(val, "Wrong Y field"); + y = (BigInteger) val.getValue(); + } + catch (IOException x) + { + InvalidParameterException e = new InvalidParameterException(x.getMessage()); + e.initCause(x); + throw e; + } + return new DSSPublicKey(Registry.X509_ENCODING_ID, p, q, g, y); + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for private keys"); + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java b/libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java new file mode 100644 index 000000000..de3668c01 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSPrivateKey.java @@ -0,0 +1,205 @@ +/* DSSPrivateKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.PrivateKey; +import java.security.interfaces.DSAPrivateKey; + +/** + * An object that embodies a DSS (Digital Signature Standard) private key. + * + * @see #getEncoded + */ +public class DSSPrivateKey + extends DSSKey + implements PrivateKey, DSAPrivateKey +{ + /** + * A randomly or pseudorandomly generated integer with 0 < x < + * q. + */ + private final BigInteger x; + + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Convenience constructor. Calls the constructor with 5 arguments passing + * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred + * encoding format. + * + * @param p the public modulus. + * @param q the public prime divisor of p-1. + * @param g a generator of the unique cyclic group Z* + * p. + * @param x the private key part. + */ + public DSSPrivateKey(BigInteger p, BigInteger q, BigInteger g, BigInteger x) + { + this(Registry.RAW_ENCODING_ID, p, q, g, x); + } + + /** + * Constructs a new instance of a DSSPrivateKey given the + * designated arguments. + * + * @param preferredFormat the indetifier of the preferred encoding format to + * use when externalizing this key. + * @param p the public modulus. + * @param q the public prime divisor of p-1. + * @param g a generator of the unique cyclic group Z* + * p. + * @param x the private key part. + */ + public DSSPrivateKey(int preferredFormat, BigInteger p, BigInteger q, + BigInteger g, BigInteger x) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID + : preferredFormat, + p, q, g); + this.x = x; + } + + /** + * A class method that takes the output of the encodePrivateKey() + * method of a DSS keypair codec object (an instance implementing + * {@link gnu.java.security.key.IKeyPairCodec} for DSS keys, and re-constructs + * an instance of this object. + * + * @param k the contents of a previously encoded instance of this object. + * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an + * instance of this object. + * @exception IllegalArgumentException if the byte sequence does not represent + * a valid encoding of an instance of this object. + */ + public static DSSPrivateKey valueOf(byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_DSS_PRIVATE_KEY[0]) + try + { + return (DSSPrivateKey) new DSSKeyPairRawCodec().decodePrivateKey(k); + } + catch (IllegalArgumentException ignored) + { + } + // try PKCS#8 codec + return (DSSPrivateKey) new DSSKeyPairPKCS8Codec().decodePrivateKey(k); + } + + public BigInteger getX() + { + return x; + } + + /** + * Returns the encoded form of this private key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @exception IllegalArgumentException if the format is not supported. + * @see DSSKeyPairRawCodec + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new DSSKeyPairRawCodec().encodePrivateKey(this); + break; + case IKeyPairCodec.PKCS8_FORMAT: + result = new DSSKeyPairPKCS8Codec().encodePrivateKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + * Returns true if the designated object is an instance of + * {@link DSAPrivateKey} and has the same DSS (Digital Signature Standard) + * parameter values as this one. + * + * @param obj the other non-null DSS key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + + if (! (obj instanceof DSAPrivateKey)) + return false; + + DSAPrivateKey that = (DSAPrivateKey) obj; + return super.equals(that) && x.equals(that.getX()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new CPStringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("x=0x").append(Configuration.DEBUG ? x.toString(16) + : "**...*").append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java b/libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java new file mode 100644 index 000000000..d7c1afe15 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/DSSPublicKey.java @@ -0,0 +1,203 @@ +/* DSSPublicKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.PublicKey; +import java.security.interfaces.DSAPublicKey; + +/** + * An object that embodies a DSS (Digital Signature Standard) public key. + * + * @see #getEncoded + */ +public class DSSPublicKey + extends DSSKey + implements PublicKey, DSAPublicKey +{ + /** + * y = gx mod p where x is the + * private part of the DSA key. + */ + private final BigInteger y; + + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Conveience constructor. Calls the constructor with 5 arguments passing + * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred + * encoding format. + * + * @param p the public modulus. + * @param q the public prime divisor of p-1. + * @param g a generator of the unique cyclic group Z* + * p. + * @param y the public key part. + */ + public DSSPublicKey(BigInteger p, BigInteger q, BigInteger g, BigInteger y) + { + this(Registry.RAW_ENCODING_ID, p, q, g, y); + } + + /** + * Constructs a new instance of DSSPublicKey given the + * designated arguments. + * + * @param preferredFormat the identifier of the preferred encoding format to + * use when externalizing this key. + * @param p the public modulus. + * @param q the public prime divisor of p-1. + * @param g a generator of the unique cyclic group Z* + * p. + * @param y the public key part. + */ + public DSSPublicKey(int preferredFormat, BigInteger p, BigInteger q, + BigInteger g, BigInteger y) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID + : preferredFormat, + p, q, g); + this.y = y; + } + + /** + * A class method that takes the output of the encodePublicKey() + * method of a DSS keypair codec object (an instance implementing + * {@link gnu.java.security.key.IKeyPairCodec} for DSS keys, and re-constructs + * an instance of this object. + * + * @param k the contents of a previously encoded instance of this object. + * @exception ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an + * instance of this object. + * @exception IllegalArgumentException if the byte sequence does not represent + * a valid encoding of an instance of this object. + */ + public static DSSPublicKey valueOf(byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_DSS_PUBLIC_KEY[0]) + try + { + return (DSSPublicKey) new DSSKeyPairRawCodec().decodePublicKey(k); + } + catch (IllegalArgumentException ignored) + { + } + // try X.509 codec + return (DSSPublicKey) new DSSKeyPairX509Codec().decodePublicKey(k); + } + + public BigInteger getY() + { + return y; + } + + /** + * Returns the encoded form of this public key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @exception IllegalArgumentException if the format is not supported. + * @see DSSKeyPairRawCodec + */ + public byte[] getEncoded(int format) + { + byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new DSSKeyPairRawCodec().encodePublicKey(this); + break; + case IKeyPairCodec.X509_FORMAT: + result = new DSSKeyPairX509Codec().encodePublicKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + * Returns true if the designated object is an instance of + * {@link DSAPublicKey} and has the same DSS (Digital Signature Standard) + * parameter values as this one. + * + * @param obj the other non-null DSS key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(Object obj) + { + if (obj == null) + return false; + + if (! (obj instanceof DSAPublicKey)) + return false; + + DSAPublicKey that = (DSAPublicKey) obj; + return super.equals(that) && y.equals(that.getY()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new CPStringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("y=0x").append(y.toString(16)).append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/java/security/key/dss/FIPS186.java b/libjava/classpath/gnu/java/security/key/dss/FIPS186.java new file mode 100644 index 000000000..5d371e10c --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/dss/FIPS186.java @@ -0,0 +1,262 @@ +/* FIPS186.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.dss; + +import gnu.java.security.hash.Sha160; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.SecureRandom; + +/** + * An implementation of the DSA parameters generation as described in FIPS-186. + *

+ * References: + *

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

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

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

+ * References: + *

    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ */ +public class GnuRSAPrivateKey + extends GnuRSAKey + implements PrivateKey, RSAPrivateCrtKey +{ + /** The first prime divisor of the modulus. */ + private final BigInteger p; + + /** The second prime divisor of the modulus. */ + private final BigInteger q; + + /** The private exponent of an RSA private key. */ + private final BigInteger d; + + /** The first factor's exponent. */ + private final BigInteger dP; + + /** The second factor's exponent. */ + private final BigInteger dQ; + + /** The CRT (Chinese Remainder Theorem) coefficient. */ + private final BigInteger qInv; + + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Convenience constructor. Calls the constructor with 5 arguments passing + * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred + * encoding format. + * + * @param p the modulus first prime divisor. + * @param q the modulus second prime divisor. + * @param e the public exponent. + * @param d the private exponent. + */ + public GnuRSAPrivateKey(BigInteger p, BigInteger q, BigInteger e, BigInteger d) + { + this(Registry.RAW_ENCODING_ID, p, q, e, d); + } + + /** + * Constructs a new instance of a GnuRSAPrivateKey given the + * designated arguments. + * + * @param preferredFormat the indetifier of the preferred encoding format to + * use when externalizing this key. + * @param p the modulus first prime divisor. + * @param q the modulus second prime divisor. + * @param e the public exponent. + * @param d the private exponent. + */ + public GnuRSAPrivateKey(int preferredFormat, BigInteger p, BigInteger q, + BigInteger e, BigInteger d) + { + this(preferredFormat, + p.multiply(q), + e, d, p, q, + e.modInverse(p.subtract(BigInteger.ONE)), + e.modInverse(q.subtract(BigInteger.ONE)), + q.modInverse(p)); + } + + /** + * Constructs a new instance of a GnuRSAPrivateKey given the + * designated arguments. + * + * @param preferredFormat the indetifier of the preferred encoding format to + * use when externalizing this key. + * @param n the public modulus, which is also the product of p + * and q. + * @param e the public exponent. + * @param d the private exponent. + * @param p the modulus first prime divisor. + * @param q the modulus second prime divisor. + * @param dP the first prime's exponen. A positive integer less than + * p and q, satisfying + * e * dP = 1 (mod p-1). + * @param dQ the second prime's exponent. A positive integer less than + * p and q, satisfying + * e * dQ = 1 (mod p-1). + * @param qInv the Chinese Remainder Theorem coefiicient. A positive integer + * less than p, satisfying + * q * qInv = 1 (mod p). + */ + public GnuRSAPrivateKey(int preferredFormat, BigInteger n, BigInteger e, + BigInteger d, BigInteger p, BigInteger q, + BigInteger dP, BigInteger dQ, BigInteger qInv) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.PKCS8_ENCODING_ID + : preferredFormat, + n, e); + this.d = d; + this.p = p; + this.q = q; + // the exponents dP and dQ are positive integers less than p and q + // respectively satisfying + // e * dP = 1 (mod p-1); + // e * dQ = 1 (mod q-1), + this.dP = dP; + this.dQ = dQ; + // the CRT coefficient qInv is a positive integer less than p satisfying + // q * qInv = 1 (mod p). + this.qInv = qInv; + } + + /** + * A class method that takes the output of the encodePrivateKey() + * method of an RSA keypair codec object (an instance implementing + * {@link IKeyPairCodec} for RSA keys, and re-constructs an instance of this + * object. + * + * @param k the contents of a previously encoded instance of this object. + * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an instance + * of this object. + * @throws IllegalArgumentException if the byte sequence does not represent a + * valid encoding of an instance of this object. + */ + public static GnuRSAPrivateKey valueOf(final byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_RSA_PRIVATE_KEY[0]) + try + { + return (GnuRSAPrivateKey) new RSAKeyPairRawCodec().decodePrivateKey(k); + } + catch (IllegalArgumentException ignored) + { + } + // try PKCS#8 codec + return (GnuRSAPrivateKey) new RSAKeyPairPKCS8Codec().decodePrivateKey(k); + } + + public BigInteger getPrimeP() + { + return p; + } + + public BigInteger getPrimeQ() + { + return q; + } + + public BigInteger getPrimeExponentP() + { + return dP; + } + + public BigInteger getPrimeExponentQ() + { + return dQ; + } + + public BigInteger getCrtCoefficient() + { + return qInv; + } + + public BigInteger getPrivateExponent() + { + return d; + } + + /** + * Returns the encoded form of this private key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @throws IllegalArgumentException if the format is not supported. + * @see RSAKeyPairRawCodec + * @see RSAKeyPairPKCS8Codec + */ + public byte[] getEncoded(int format) + { + final byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new RSAKeyPairRawCodec().encodePrivateKey(this); + break; + case IKeyPairCodec.PKCS8_FORMAT: + result = new RSAKeyPairPKCS8Codec().encodePrivateKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + * Returns true if the designated object is an instance of this + * class and has the same RSA parameter values as this one. + * + * @param obj the other non-null RSA key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(final Object obj) + { + if (obj == null) + return false; + + if (obj instanceof RSAPrivateKey) + { + final RSAPrivateKey that = (RSAPrivateKey) obj; + return super.equals(that) && d.equals(that.getPrivateExponent()); + } + if (obj instanceof RSAPrivateCrtKey) + { + final RSAPrivateCrtKey that = (RSAPrivateCrtKey) obj; + return super.equals(that) && p.equals(that.getPrimeP()) + && q.equals(that.getPrimeQ()) + && dP.equals(that.getPrimeExponentP()) + && dQ.equals(that.getPrimeExponentQ()) + && qInv.equals(that.getCrtCoefficient()); + } + return false; + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new CPStringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append("d=0x").append(Configuration.DEBUG ? d.toString(16) + : "**...*").append(ls) + .append("p=0x").append(Configuration.DEBUG ? p.toString(16) + : "**...*").append(ls) + .append("q=0x").append(Configuration.DEBUG ? q.toString(16) + : "**...*").append(ls) + .append("dP=0x").append(Configuration.DEBUG ? dP.toString(16) + : "**...*").append(ls) + .append("dQ=0x").append(Configuration.DEBUG ? dQ.toString(16) + : "**...*").append(ls) + .append("qInv=0x").append(Configuration.DEBUG ? qInv.toString(16) + : "**...*").append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPublicKey.java b/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPublicKey.java new file mode 100644 index 000000000..0bad92881 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/GnuRSAPublicKey.java @@ -0,0 +1,190 @@ +/* GnuRSAPublicKey.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import gnu.java.lang.CPStringBuilder; + +import gnu.java.security.Registry; +import gnu.java.security.action.GetPropertyAction; +import gnu.java.security.key.IKeyPairCodec; + +import java.math.BigInteger; +import java.security.AccessController; +import java.security.PublicKey; +import java.security.interfaces.RSAPublicKey; + +/** + * An object that encapsulates an RSA public key. + *

+ * References: + *

    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ */ +public class GnuRSAPublicKey + extends GnuRSAKey + implements PublicKey, RSAPublicKey +{ + /** String representation of this key. Cached for speed. */ + private transient String str; + + /** + * Conveience constructor. Calls the constructor with 3 arguments passing + * {@link Registry#RAW_ENCODING_ID} as the identifier of the preferred + * encoding format. + * + * @param n the modulus. + * @param e the public exponent. + */ + public GnuRSAPublicKey(final BigInteger n, final BigInteger e) + { + this(Registry.RAW_ENCODING_ID, n, e); + } + + /** + * Constructs a new instance of GnuRSAPublicKey given the + * designated arguments. + * + * @param preferredFormat the identifier of the preferred encoding format to + * use when externalizing this key. + * @param n the modulus. + * @param e the public exponent. + */ + public GnuRSAPublicKey(int preferredFormat, BigInteger n, BigInteger e) + { + super(preferredFormat == Registry.ASN1_ENCODING_ID ? Registry.X509_ENCODING_ID + : preferredFormat, + n, e); + } + + /** + * A class method that takes the output of the encodePublicKey() + * method of an RSA keypair codec object (an instance implementing + * {@link IKeyPairCodec} for RSA keys, and re-constructs an instance of this + * object. + * + * @param k the contents of a previously encoded instance of this object. + * @throws ArrayIndexOutOfBoundsException if there is not enough bytes, in + * k, to represent a valid encoding of an instance + * of this object. + * @throws IllegalArgumentException if the byte sequence does not represent a + * valid encoding of an instance of this object. + */ + public static GnuRSAPublicKey valueOf(final byte[] k) + { + // try RAW codec + if (k[0] == Registry.MAGIC_RAW_RSA_PUBLIC_KEY[0]) + try + { + return (GnuRSAPublicKey) new RSAKeyPairRawCodec().decodePublicKey(k); + } + catch (IllegalArgumentException ignored) + { + } + // try X.509 codec + return (GnuRSAPublicKey) new RSAKeyPairX509Codec().decodePublicKey(k); + } + + /** + * Returns the encoded form of this public key according to the designated + * format. + * + * @param format the desired format identifier of the resulting encoding. + * @return the byte sequence encoding this key according to the designated + * format. + * @throws IllegalArgumentException if the format is not supported. + * @see RSAKeyPairRawCodec + */ + public byte[] getEncoded(final int format) + { + final byte[] result; + switch (format) + { + case IKeyPairCodec.RAW_FORMAT: + result = new RSAKeyPairRawCodec().encodePublicKey(this); + break; + case IKeyPairCodec.X509_FORMAT: + result = new RSAKeyPairX509Codec().encodePublicKey(this); + break; + default: + throw new IllegalArgumentException("Unsupported encoding format: " + + format); + } + return result; + } + + /** + * Returns true if the designated object is an instance of this + * class and has the same RSA parameter values as this one. + * + * @param obj the other non-null RSA key to compare to. + * @return true if the designated object is of the same type + * and value as this one. + */ + public boolean equals(final Object obj) + { + if (obj == null) + return false; + + if (! (obj instanceof RSAPublicKey)) + return false; + + final RSAPublicKey that = (RSAPublicKey) obj; + return super.equals(that) + && getPublicExponent().equals(that.getPublicExponent()); + } + + public String toString() + { + if (str == null) + { + String ls = (String) AccessController.doPrivileged + (new GetPropertyAction("line.separator")); + str = new CPStringBuilder(this.getClass().getName()).append("(") + .append(super.toString()).append(",").append(ls) + .append(")") + .toString(); + } + return str; + } +} diff --git a/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairGenerator.java b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairGenerator.java new file mode 100644 index 000000000..bec60d350 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairGenerator.java @@ -0,0 +1,246 @@ +/* RSAKeyPairGenerator.java -- + Copyright 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.key.IKeyPairGenerator; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.KeyPair; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.SecureRandom; +import java.security.spec.RSAKeyGenParameterSpec; +import java.util.Map; +import java.util.logging.Logger; + +/** + * A key-pair generator for asymetric keys to use in conjunction with the RSA + * scheme. + *

+ * Reference: + *

    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B. Primitive specification + * and supporting documentation. Jakob Jonsson and Burt Kaliski.
  2. + *
  3. Handbook of Applied + * Cryptography, Alfred J. Menezes, Paul C. van Oorschot and Scott A. + * Vanstone. Section 11.3 RSA and related signature schemes.
  4. + *
+ */ +public class RSAKeyPairGenerator + implements IKeyPairGenerator +{ + private static final Logger log = Logger.getLogger(RSAKeyPairGenerator.class.getName()); + + /** The BigInteger constant 1. */ + private static final BigInteger ONE = BigInteger.ONE; + + /** The BigInteger constant 2. */ + private static final BigInteger TWO = BigInteger.valueOf(2L); + + /** Property name of the length (Integer) of the modulus of an RSA key. */ + public static final String MODULUS_LENGTH = "gnu.crypto.rsa.L"; + + /** + * Property name of an optional {@link SecureRandom} instance to use. The + * default is to use a classloader singleton from {@link PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.rsa.prng"; + + /** + * Property name of an optional {@link RSAKeyGenParameterSpec} instance to use + * for this generator's n, and e values. The + * default is to generate n and use a fixed value for + * e (Fermat's F4 number). + */ + public static final String RSA_PARAMETERS = "gnu.crypto.rsa.params"; + + /** + * Property name of the preferred encoding format to use when externalizing + * generated instance of key-pairs from this generator. The property is taken + * to be an {@link Integer} that encapsulates an encoding format identifier. + */ + public static final String PREFERRED_ENCODING_FORMAT = "gnu.crypto.rsa.encoding"; + + /** Default value for the modulus length. */ + private static final int DEFAULT_MODULUS_LENGTH = 1024; + + /** Default encoding format to use when none was specified. */ + private static final int DEFAULT_ENCODING_FORMAT = Registry.RAW_ENCODING_ID; + + /** The desired bit length of the modulus. */ + private int L; + + /** + * This implementation uses, by default, Fermat's F4 number as the public + * exponent. + */ + private BigInteger e = BigInteger.valueOf(65537L); + + /** The optional {@link SecureRandom} instance to use. */ + private SecureRandom rnd = null; + + /** Our default source of randomness. */ + private PRNG prng = null; + + /** Preferred encoding format of generated keys. */ + private int preferredFormat; + + // implicit 0-arguments constructor + + public String name() + { + return Registry.RSA_KPG; + } + + /** + * Configures this instance. + * + * @param attributes the map of name/value pairs to use. + * @exception IllegalArgumentException if the designated MODULUS_LENGTH value + * is less than 1024. + */ + public void setup(Map attributes) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "setup", attributes); + // do we have a SecureRandom, or should we use our own? + rnd = (SecureRandom) attributes.get(SOURCE_OF_RANDOMNESS); + // are we given a set of RSA params or we shall use our own? + RSAKeyGenParameterSpec params = (RSAKeyGenParameterSpec) attributes.get(RSA_PARAMETERS); + // find out the modulus length + if (params != null) + { + L = params.getKeysize(); + e = params.getPublicExponent(); + } + else + { + Integer l = (Integer) attributes.get(MODULUS_LENGTH); + L = (l == null ? DEFAULT_MODULUS_LENGTH : l.intValue()); + } + if (L < 1024) + throw new IllegalArgumentException(MODULUS_LENGTH); + + // what is the preferred encoding format + Integer formatID = (Integer) attributes.get(PREFERRED_ENCODING_FORMAT); + preferredFormat = formatID == null ? DEFAULT_ENCODING_FORMAT + : formatID.intValue(); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "setup"); + } + + /** + *

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

+ * + * @return an RSA keypair. + */ + public KeyPair generate() + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "generate"); + BigInteger p, q, n, d; + // 1. Generate a prime p in the interval [2**(M-1), 2**M - 1], where + // M = CEILING(L/2), and such that GCD(p, e) = 1 + int M = (L + 1) / 2; + BigInteger lower = TWO.pow(M - 1); + BigInteger upper = TWO.pow(M).subtract(ONE); + byte[] kb = new byte[(M + 7) / 8]; // enough bytes to frame M bits + step1: while (true) + { + nextRandomBytes(kb); + p = new BigInteger(1, kb).setBit(0); + if (p.compareTo(lower) >= 0 && p.compareTo(upper) <= 0 + && p.isProbablePrime(80) && p.gcd(e).equals(ONE)) + break step1; + } + // 2. Generate a prime q such that the product of p and q is an L-bit + // number, and such that GCD(q, e) = 1 + step2: while (true) + { + nextRandomBytes(kb); + q = new BigInteger(1, kb).setBit(0); + n = p.multiply(q); + if (n.bitLength() == L && q.isProbablePrime(80) && q.gcd(e).equals(ONE)) + break step2; + // TODO: test for p != q + } + // TODO: ensure p < q + // 3. Put n = pq. The public key is (n, e). + // 4. Compute the parameters necessary for the private key K (see + // Section 2.2). + BigInteger phi = p.subtract(ONE).multiply(q.subtract(ONE)); + d = e.modInverse(phi); + // 5. Output the public key and the private key. + PublicKey pubK = new GnuRSAPublicKey(preferredFormat, n, e); + PrivateKey secK = new GnuRSAPrivateKey(preferredFormat, p, q, e, d); + KeyPair result = new KeyPair(pubK, secK); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "generate", result); + return result; + } + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + private void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else + getDefaultPRNG().nextBytes(buffer); + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java new file mode 100644 index 000000000..2785f02c8 --- /dev/null +++ b/libjava/classpath/gnu/java/security/key/rsa/RSAKeyPairPKCS8Codec.java @@ -0,0 +1,299 @@ +/* RSAKeyPairPKCS8Codec.java -- PKCS#8 Encoding/Decoding handler + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.key.rsa; + +import gnu.java.security.Configuration; +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERReader; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.key.IKeyPairCodec; +import gnu.java.security.util.DerUtil; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.math.BigInteger; +import java.security.InvalidParameterException; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.ArrayList; +import java.util.logging.Logger; + +/** + * An implementation of an {@link IKeyPairCodec} that knows how to encode / + * decode PKCS#8 ASN.1 external representation of RSA private keys. + */ +public class RSAKeyPairPKCS8Codec + implements IKeyPairCodec +{ + private static final Logger log = Logger.getLogger(RSAKeyPairPKCS8Codec.class.getName()); + private static final OID RSA_ALG_OID = new OID(Registry.RSA_OID_STRING); + + // implicit 0-arguments constructor + + public int getFormatID() + { + return PKCS8_FORMAT; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePublicKey(PublicKey key) + { + throw new InvalidParameterException("Wrong format for public keys"); + } + + /** + * Returns the PKCS#8 ASN.1 PrivateKeyInfo representation of an RSA + * private key. The ASN.1 specification is as follows: + *
+   *   PrivateKeyInfo ::= SEQUENCE {
+   *     version              INTEGER, -- MUST be 0
+   *     privateKeyAlgorithm  AlgorithmIdentifier,
+   *     privateKey           OCTET STRING
+   *   }
+   *
+   *   AlgorithmIdentifier ::= SEQUENCE {
+   *     algorithm   OBJECT IDENTIFIER,
+   *     parameters  ANY DEFINED BY algorithm OPTIONAL
+   *   }
+   * 
+ *

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

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

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

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

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

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

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

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

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

+   *   RSAPublicKey ::= SEQUENCE {
+   *     modulus         INTEGER, -- n
+   *     publicExponent  INTEGER  -- e
+   *   }
+   * 
+ * + * @param key the {@link PublicKey} instance to encode. MUST be an instance of + * {@link GnuRSAPublicKey}. + * @return the ASN.1 representation of the SubjectPublicKeyInfo in an + * X.509 certificate. + * @throw InvalidParameterException if key is not an instance + * of {@link GnuRSAPublicKey} or if an exception occurs during the + * marshalling process. + */ + public byte[] encodePublicKey(PublicKey key) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "encodePublicKey()", key); + if (! (key instanceof GnuRSAPublicKey)) + throw new InvalidParameterException("key"); + + DERValue derOID = new DERValue(DER.OBJECT_IDENTIFIER, RSA_ALG_OID); + + GnuRSAPublicKey rsaKey = (GnuRSAPublicKey) key; + BigInteger n = rsaKey.getN(); + BigInteger e = rsaKey.getE(); + + DERValue derN = new DERValue(DER.INTEGER, n); + DERValue derE = new DERValue(DER.INTEGER, e); + + ArrayList algorithmID = new ArrayList(2); + algorithmID.add(derOID); + algorithmID.add(new DERValue(DER.NULL, null)); + DERValue derAlgorithmID = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + algorithmID); + + ArrayList publicKey = new ArrayList(2); + publicKey.add(derN); + publicKey.add(derE); + DERValue derPublicKey = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + publicKey); + byte[] spkBytes = derPublicKey.getEncoded(); + DERValue derSPK = new DERValue(DER.BIT_STRING, new BitString(spkBytes)); + + ArrayList spki = new ArrayList(2); + spki.add(derAlgorithmID); + spki.add(derSPK); + DERValue derSPKI = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, spki); + + byte[] result; + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + try + { + DERWriter.write(baos, derSPKI); + result = baos.toByteArray(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(x.getMessage()); + y.initCause(x); + throw y; + } + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "encodePublicKey()", result); + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public byte[] encodePrivateKey(PrivateKey key) + { + throw new InvalidParameterException("Wrong format for private keys"); + } + + /** + * @param input the byte array to unmarshall into a valid RSA + * {@link PublicKey} instance. MUST NOT be null. + * @return a new instance of a {@link GnuRSAPublicKey} decoded from the + * SubjectPublicKeyInfo material in an X.509 certificate. + * @throw InvalidParameterException if an exception occurs during the + * unmarshalling process. + */ + public PublicKey decodePublicKey(byte[] input) + { + if (Configuration.DEBUG) + log.entering(this.getClass().getName(), "decodePublicKey()", input); + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + BigInteger n, e; + DERReader der = new DERReader(input); + try + { + DERValue derSPKI = der.read(); + DerUtil.checkIsConstructed(derSPKI, "Wrong SubjectPublicKeyInfo field"); + + DERValue derAlgorithmID = der.read(); + DerUtil.checkIsConstructed(derAlgorithmID, "Wrong AlgorithmIdentifier field"); + + DERValue derOID = der.read(); + if (! (derOID.getValue() instanceof OID)) + throw new InvalidParameterException("Wrong Algorithm field"); + + OID algOID = (OID) derOID.getValue(); + if (! algOID.equals(RSA_ALG_OID)) + throw new InvalidParameterException("Unexpected OID: " + algOID); + + // rfc-2459 states that this field is OPTIONAL but NULL if/when present + DERValue val = der.read(); + if (val.getTag() == DER.NULL) + val = der.read(); + + if (! (val.getValue() instanceof BitString)) + throw new InvalidParameterException("Wrong SubjectPublicKey field"); + + byte[] spkBytes = ((BitString) val.getValue()).toByteArray(); + + der = new DERReader(spkBytes); + val = der.read(); + DerUtil.checkIsConstructed(derAlgorithmID, "Wrong subjectPublicKey field"); + + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong modulus field"); + n = (BigInteger) val.getValue(); + val = der.read(); + DerUtil.checkIsBigInteger(val, "Wrong publicExponent field"); + e = (BigInteger) val.getValue(); + } + catch (IOException x) + { + InvalidParameterException y = new InvalidParameterException(x.getMessage()); + y.initCause(x); + throw y; + } + PublicKey result = new GnuRSAPublicKey(Registry.X509_ENCODING_ID, n, e); + if (Configuration.DEBUG) + log.exiting(this.getClass().getName(), "decodePublicKey()", result); + return result; + } + + /** + * @throws InvalidParameterException ALWAYS. + */ + public PrivateKey decodePrivateKey(byte[] input) + { + throw new InvalidParameterException("Wrong format for private keys"); + } +} diff --git a/libjava/classpath/gnu/java/security/package.html b/libjava/classpath/gnu/java/security/package.html new file mode 100644 index 000000000..bb6e91d61 --- /dev/null +++ b/libjava/classpath/gnu/java/security/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security + + +

+ + + diff --git a/libjava/classpath/gnu/java/security/pkcs/PKCS7Data.java b/libjava/classpath/gnu/java/security/pkcs/PKCS7Data.java new file mode 100644 index 000000000..c6474f081 --- /dev/null +++ b/libjava/classpath/gnu/java/security/pkcs/PKCS7Data.java @@ -0,0 +1,69 @@ +/* PKCS7Data.java -- Reader/writer for PKCS#7 Data objects + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.pkcs; + +import gnu.java.security.OID; + +/** + * A read/write helper class for PKCS#7 Data ASN.1 structures. + */ +public class PKCS7Data +{ + public static final OID PKCS7_DATA = new OID("1.2.840.113549.1.7.1"); + + private byte[] content; + + /** + * Constructs a new instance of PKCS7Data with the possibly + * null (implicetly referenced) content data. + * + * @param data the raw bytes of the data to use in a PKCS#7 framework. + */ + public PKCS7Data(byte[] data) + { + super(); + + this.content = data; + } + + public byte[] getEncoded() + { + return content; + } +} diff --git a/libjava/classpath/gnu/java/security/pkcs/PKCS7SignedData.java b/libjava/classpath/gnu/java/security/pkcs/PKCS7SignedData.java new file mode 100644 index 000000000..adb00a3be --- /dev/null +++ b/libjava/classpath/gnu/java/security/pkcs/PKCS7SignedData.java @@ -0,0 +1,485 @@ +/* PKCS7SignedData.java -- reader/writer for PKCS#7 signedData objects + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.security.pkcs; + +import gnu.java.security.Configuration; +import gnu.java.security.OID; +import gnu.java.security.ber.BER; +import gnu.java.security.ber.BEREncodingException; +import gnu.java.security.ber.BERReader; +import gnu.java.security.ber.BERValue; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.util.Util; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.math.BigInteger; +import java.security.cert.CRL; +import java.security.cert.CRLException; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactory; +import java.security.cert.X509CRL; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.logging.Logger; + +/** + * The SignedData object in PKCS #7. This is a read-only implementation of + * this format, and is used to provide signed Jar file support. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class PKCS7SignedData +{ + private static final Logger log = Logger.getLogger(PKCS7SignedData.class.getName()); + + public static final OID PKCS7_SIGNED_DATA = new OID("1.2.840.113549.1.7.2"); + + private BigInteger version; + private Set digestAlgorithms; + private OID contentType; + private byte[] content; + private Certificate[] certificates; + private CRL[] crls; + private Set signerInfos; + + public PKCS7SignedData(InputStream in) + throws CRLException, CertificateException, IOException + { + this(new BERReader(in)); + } + + /** + * Parse an encoded PKCS#7 SignedData object. The ASN.1 format of this + * object is: + * + *
+   * SignedData ::= SEQUENCE {
+   *   version           Version, -- always 1 for PKCS7 v1.5
+   *   digestAlgorithms  DigestAlgorithmIdentifiers,
+   *   contentInfo       ContentInfo,
+   *   certificates  [0] IMPLICIT ExtendedCertificatesAndCertificates OPTIONAL,
+   *   crls          [1] IMPLICIT CertificateRevocationLists OPTIONAL,
+   *   signerInfos       SignerInfos }
+   *
+   * Version ::= INTEGER
+   *
+   * DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier
+   *
+   * DigestAlgorithmIdentifier ::= AlgorithmIdentifier
+   *
+   * ContentInfo ::= SEQUENCE {
+   *   contentType   ContentType,
+   *   content   [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL }
+   *
+   * ContentType ::= OBJECT IDENTIFIER
+   *
+   * ExtendedCertificatesAndCertificates ::=
+   *   SET OF ExtendedCertificatesAndCertificate
+   *
+   * ExtendedCertificatesAndCertificate ::= CHOICE {
+   *   certificate             Certificate, -- from X.509
+   *   extendedCertificate [0] IMPLICIT ExtendedCertificate }
+   *
+   * CertificateRevocationLists ::= SET OF CertificateRevocationList
+   *   -- from X.509
+   *
+   * SignerInfos ::= SET OF SignerInfo
+   *
+   * SignerInfo ::= SEQUENCE {
+   *   version                       Version, -- always 1 for PKCS7 v1.5
+   *   issuerAndSerialNumber         IssuerAndSerialNumber,
+   *   digestAlgorithm               DigestAlgorithmIdentifier,
+   *   authenticatedAttributes   [0] IMPLICIT Attributes OPTIONAL,
+   *   digestEncryptionAlgorithm     DigestEncryptionAlgorithmIdentifier,
+   *   encryptedDigest               EncryptedDigest,
+   *   unauthenticatedAttributes [1] IMPLICIT Attributes OPTIONAL }
+   *
+   * EncryptedDigest ::= OCTET STRING
+   * 
+ * + *

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

+ */ + public PKCS7SignedData(BERReader ber) + throws CRLException, CertificateException, IOException + { + CertificateFactory x509 = CertificateFactory.getInstance("X509"); + DERValue val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed ContentInfo"); + + val = ber.read(); + if (val.getTag() != BER.OBJECT_IDENTIFIER) + throw new BEREncodingException("malformed ContentType"); + + if (!PKCS7_SIGNED_DATA.equals(val.getValue())) + throw new BEREncodingException("content is not SignedData"); + + val = ber.read(); + if (val.getTag() != 0) + throw new BEREncodingException("malformed Content"); + + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed SignedData"); + + if (Configuration.DEBUG) + log.fine("SignedData: " + val); + + val = ber.read(); + if (val.getTag() != BER.INTEGER) + throw new BEREncodingException("expecting Version"); + version = (BigInteger) val.getValue(); + if (Configuration.DEBUG) + log.fine(" Version: " + version); + + digestAlgorithms = new HashSet(); + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed DigestAlgorithmIdentifiers"); + if (Configuration.DEBUG) + log.fine(" DigestAlgorithmIdentifiers: " + val); + int count = 0; + DERValue val2 = ber.read(); + while (val2 != BER.END_OF_SEQUENCE && + (val.getLength() > 0 && val.getLength() > count)) + { + if (!val2.isConstructed()) + throw new BEREncodingException("malformed AlgorithmIdentifier"); + if (Configuration.DEBUG) + log.fine(" AlgorithmIdentifier: " + val2); + count += val2.getEncodedLength(); + val2 = ber.read(); + if (val2.getTag() != BER.OBJECT_IDENTIFIER) + throw new BEREncodingException("malformed AlgorithmIdentifier"); + if (Configuration.DEBUG) + log.fine(" digestAlgorithmIdentifiers OID: " + val2.getValue()); + List algId = new ArrayList(2); + algId.add(val2.getValue()); + val2 = ber.read(); + if (val2 != BER.END_OF_SEQUENCE) + { + count += val2.getEncodedLength(); + if (val2.getTag() == BER.NULL) + algId.add(null); + else + algId.add(val2.getEncoded()); + + if (val2.isConstructed()) + ber.skip(val2.getLength()); + + if (BERValue.isIndefinite(val)) + val2 = ber.read(); + } + else + algId.add(null); + + if (Configuration.DEBUG) + { + log.fine(" digestAlgorithmIdentifiers params: "); + log.fine(Util.dumpString((byte[]) algId.get(1), + " digestAlgorithmIdentifiers params: ")); + } + digestAlgorithms.add(algId); + } + + val = ber.read(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed ContentInfo"); + if (Configuration.DEBUG) + log.fine(" ContentInfo: " + val); + val2 = ber.read(); + if (val2.getTag() != BER.OBJECT_IDENTIFIER) + throw new BEREncodingException("malformed ContentType"); + + contentType = (OID) val2.getValue(); + if (Configuration.DEBUG) + log.fine(" ContentType OID: " + contentType); + if (BERValue.isIndefinite(val) + || (val.getLength() > 0 && val.getLength() > val2.getEncodedLength())) + { + val2 = ber.read(); + if (val2 != BER.END_OF_SEQUENCE) + { + content = val2.getEncoded(); + if (BERValue.isIndefinite(val)) + val2 = ber.read(); + } + } + if (Configuration.DEBUG) + { + log.fine(" Content: "); + log.fine(Util.dumpString(content, " Content: ")); + } + val = ber.read(); + if (val.getTag() == 0) + { + if (!val.isConstructed()) + throw new BEREncodingException("malformed ExtendedCertificatesAndCertificates"); + if (Configuration.DEBUG) + log.fine(" ExtendedCertificatesAndCertificates: " + val); + count = 0; + val2 = ber.read(); + List certs = new LinkedList(); + while (val2 != BER.END_OF_SEQUENCE && + (val.getLength() > 0 && val.getLength() > count)) + { + Certificate cert = + x509.generateCertificate(new ByteArrayInputStream(val2.getEncoded())); + if (Configuration.DEBUG) + log.fine(" Certificate: " + cert); + certs.add(cert); + count += val2.getEncodedLength(); + ber.skip(val2.getLength()); + if (BERValue.isIndefinite(val) || val.getLength() > count) + val2 = ber.read(); + } + certificates = (Certificate[]) certs.toArray(new Certificate[certs.size()]); + val = ber.read(); + } + + if (val.getTag() == 1) + { + if (!val.isConstructed()) + throw new BEREncodingException("malformed CertificateRevocationLists"); + if (Configuration.DEBUG) + log.fine(" CertificateRevocationLists: " + val); + count = 0; + val2 = ber.read(); + List crls = new LinkedList(); + while (val2 != BER.END_OF_SEQUENCE && + (val.getLength() > 0 && val.getLength() > count)) + { + CRL crl = x509.generateCRL(new ByteArrayInputStream(val2.getEncoded())); + if (Configuration.DEBUG) + log.fine(" CRL: " + crl); + crls.add(crl); + count += val2.getEncodedLength(); + ber.skip(val2.getLength()); + if (BERValue.isIndefinite(val) || val.getLength() > count) + val2 = ber.read(); + } + this.crls = (CRL[]) crls.toArray(new CRL[crls.size()]); + val = ber.read(); + } + + signerInfos = new HashSet(); + if (!val.isConstructed()) + throw new BEREncodingException("malformed SignerInfos"); + if (Configuration.DEBUG) + log.fine(" SignerInfos: " + val); + + // FIXME read this more carefully. + // Since we are just reading a file (probably) we just read until we + // reach the end. + while (true) + { + int i = ber.peek(); + if (i == 0 || i == -1) + break; + signerInfos.add(new SignerInfo(ber)); + } + } + + /** + * Constructs a new instance of PKCS7SignedData given a + * designated set of fields. + * + * @param digestAlgorithms the collection of DigestAlgorithm elements. Each + * DigestAlgorithm is a {@link List} of two elements, the first is an + * OID while the second is dependent on the value of the OID element. + * @param data an instance of a PKCS#7 (non-signed) data. In its simplest form + * such an ASN.1 structure would consist of just the OID of a + * non-signed PKCS#7 Data. + * @param certificates the array of Certificates used to authenticate the + * enclosed (or referenced, in case the content is null) data. + * @param crls the array of certificate-revocation lists of the used + * certificates. + * @param signerInfos a set of {@link SignerInfo} elements, one per signer of + * the data referenced by this PKCS7SignedData + * instance. + */ + public PKCS7SignedData(Set digestAlgorithms, PKCS7Data data, + Certificate[] certificates, X509CRL[] crls, + Set signerInfos) + { + super(); + + this.version = BigInteger.ONE; + this.digestAlgorithms = digestAlgorithms; + this.contentType = PKCS7_SIGNED_DATA; + this.content = data == null ? null : data.getEncoded(); + this.certificates = certificates; + this.crls = crls; + this.signerInfos = signerInfos; + } + + public BigInteger getVersion() + { + return version; + } + + public Certificate[] getCertificates() + { + return (certificates != null ? (Certificate[]) certificates.clone() + : null); + } + + public OID getContentType() + { + return contentType; + } + + public byte[] getContent() + { + return (content != null ? (byte[]) content.clone() : null); + } + + public Set getDigestAlgorithms() + { + // FIXME copy contents too, they are mutable!!! + return Collections.unmodifiableSet(digestAlgorithms); + } + + public Set getSignerInfos() + { + Set copy = new HashSet(); + for (Iterator it = signerInfos.iterator(); it.hasNext(); ) + copy.add(it.next()); + return Collections.unmodifiableSet(copy); + } + + /** + * Writes to the designated output stream the DER encoding of the current + * contents of this instance. + * + * @param out the destination output stream. + * @throws IOException if an I/O related exception occurs during the process. + * @throws CRLException if an exception occurs while encoding the certificate + * revocation lists associated with this instance. + * @throws CertificateEncodingException if an exception occurs while encoding + * the certificate chains associated with this instance. + */ + public void encode(OutputStream out) throws IOException, CRLException, + CertificateEncodingException + { + DERValue derVersion = new DERValue(DER.INTEGER, version); + + DERValue derDigestAlgorithms = new DERValue(DER.CONSTRUCTED | DER.SET, + digestAlgorithms); + + DERValue derContentType = new DERValue(DER.OBJECT_IDENTIFIER, + PKCS7Data.PKCS7_DATA); + ArrayList contentInfo = new ArrayList(2); + contentInfo.add(derContentType); + if (content == null) + contentInfo.add(new DERValue(DER.NULL, null)); + else + contentInfo.add(content); + + DERValue derContentInfo = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + contentInfo); + + ByteArrayOutputStream baos = new ByteArrayOutputStream(4096); + for (int i = 0; i < certificates.length; i++) + baos.write(certificates[i].getEncoded()); + + baos.flush(); + byte[] b = baos.toByteArray(); + DERValue derExtendedCertificatesAndCertificates = + new DERValue(DER.CONSTRUCTED | DER.CONTEXT | 0, b.length, b, null); + + DERValue derCertificateRevocationLists = null; + if (crls != null && crls.length > 0) + { + baos.reset(); + for (int i = 0; i < crls.length; i++) + baos.write(((X509CRL) crls[i]).getEncoded()); + + baos.flush(); + byte[] b2 = baos.toByteArray(); + derCertificateRevocationLists = + new DERValue(DER.CONSTRUCTED | DER.CONTEXT | 1, b2.length, b2, null); + } + + baos.reset(); + for (Iterator it = signerInfos.iterator(); it.hasNext();) + { + SignerInfo signerInfo = (SignerInfo) it.next(); + signerInfo.encode(baos); + } + baos.flush(); + byte[] b3 = baos.toByteArray(); + DERValue derSignerInfos = new DERValue(DER.CONSTRUCTED | DER.SET, + b3.length, b3, null); + + ArrayList signedData = new ArrayList(6); + signedData.add(derVersion); + signedData.add(derDigestAlgorithms); + signedData.add(derContentInfo); + signedData.add(derExtendedCertificatesAndCertificates); + if (derCertificateRevocationLists != null) + signedData.add(derCertificateRevocationLists); + + signedData.add(derSignerInfos); + DERValue derSignedData = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, + signedData); + // now the outer contents + ArrayList outer = new ArrayList(3); + outer.add(new DERValue(DER.OBJECT_IDENTIFIER, PKCS7_SIGNED_DATA)); + outer.add(new DERValue(DER.CONTEXT | 0, null)); + outer.add(derSignedData); + DERValue derOuter = new DERValue(DER.CONSTRUCTED | DER.SEQUENCE, outer); + + DERWriter.write(out, derOuter); + } +} diff --git a/libjava/classpath/gnu/java/security/pkcs/SignerInfo.java b/libjava/classpath/gnu/java/security/pkcs/SignerInfo.java new file mode 100644 index 000000000..645ed67bb --- /dev/null +++ b/libjava/classpath/gnu/java/security/pkcs/SignerInfo.java @@ -0,0 +1,429 @@ +/* SignerInfo.java -- a SignerInfo object, from PKCS #7 + Copyright (C) 2004, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.security.pkcs; + +import gnu.java.security.Configuration; +import gnu.java.security.OID; +import gnu.java.security.ber.BER; +import gnu.java.security.ber.BEREncodingException; +import gnu.java.security.ber.BERReader; +import gnu.java.security.ber.BERValue; +import gnu.java.security.der.DER; +import gnu.java.security.der.DERValue; +import gnu.java.security.der.DERWriter; +import gnu.java.security.util.Util; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.logging.Logger; + +import javax.security.auth.x500.X500Principal; + +public class SignerInfo +{ + private static final Logger log = Logger.getLogger(SignerInfo.class.getName()); + + private final BigInteger version; + private final BigInteger serialNumber; + private final X500Principal issuer; + private final OID digestAlgorithmId; + private final byte[] digestAlgorithmParams; + private final byte[] authenticatedAttributes; + private final OID digestEncryptionAlgorithmId; + private final byte[] digestEncryptionAlgorithmParams; + private final byte[] encryptedDigest; + private final byte[] unauthenticatedAttributes; + + /** + * Parse a SignerInfo object. + *

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

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

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

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

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

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

+ * References: + *

    + *
  1. [HAC]: Handbook of + * Applied Cryptography.
    + * CRC Press, Inc. ISBN 0-8493-8523-7, 1997
    + * Menezes, A., van Oorschot, P. and S. Vanstone.
  2. + *
+ */ +public interface IRandom + extends Cloneable +{ + /** + * Returns the canonical name of this instance. + * + * @return the canonical name of this instance. + */ + String name(); + + /** + * Initialises the pseudo-random number generator scheme with the appropriate + * attributes. + * + * @param attributes a set of name-value pairs that describe the desired + * future instance behaviour. + * @exception IllegalArgumentException if at least one of the defined name/ + * value pairs contains invalid data. + */ + void init(Map attributes); + + /** + * Returns the next 8 bits of random data generated from this instance. + * + * @return the next 8 bits of random data generated from this instance. + * @exception IllegalStateException if the instance is not yet initialised. + * @exception LimitReachedException if this instance has reached its + * theoretical limit for generating non-repetitive pseudo-random + * data. + */ + byte nextByte() throws IllegalStateException, LimitReachedException; + + /** + * Fills the designated byte array, starting from byte at index + * offset, for a maximum of length bytes with + * the output of this generator instance. + * + * @param out the placeholder to contain the generated random bytes. + * @param offset the starting index in out to consider. This method + * does nothing if this parameter is not within 0 and + * out.length. + * @param length the maximum number of required random bytes. This method does + * nothing if this parameter is less than 1. + * @exception IllegalStateException if the instance is not yet initialised. + * @exception LimitReachedException if this instance has reached its + * theoretical limit for generating non-repetitive pseudo-random + * data. + */ + void nextBytes(byte[] out, int offset, int length) + throws IllegalStateException, LimitReachedException; + + /** + * Supplement, or possibly replace, the random state of this PRNG with a + * random byte. + *

+ * Implementations are not required to implement this method in any meaningful + * way; this may be a no-operation, and implementations may throw an + * {@link UnsupportedOperationException}. + * + * @param b The byte to add. + */ + void addRandomByte(byte b); + + /** + * Supplement, or possibly replace, the random state of this PRNG with a + * sequence of new random bytes. + *

+ * Implementations are not required to implement this method in any meaningful + * way; this may be a no-operation, and implementations may throw an + * {@link UnsupportedOperationException}. + * + * @param in The buffer of new random bytes to add. + */ + void addRandomBytes(byte[] in); + + /** + * Supplement, or possibly replace, the random state of this PRNG with a + * sequence of new random bytes. + *

+ * Implementations are not required to implement this method in any meaningful + * way; this may be a no-operation, and implementations may throw an + * {@link UnsupportedOperationException}. + * + * @param in The buffer of new random bytes to add. + * @param offset The offset from whence to begin reading random bytes. + * @param length The number of random bytes to add. + * @exception IndexOutOfBoundsException If offset, length, or + * offset+length is out of bounds. + */ + void addRandomBytes(byte[] in, int offset, int length); + + /** + * Returns a clone copy of this instance. + * + * @return a clone copy of this instance. + */ + Object clone() throws CloneNotSupportedException; +} diff --git a/libjava/classpath/gnu/java/security/prng/LimitReachedException.java b/libjava/classpath/gnu/java/security/prng/LimitReachedException.java new file mode 100644 index 000000000..028c74553 --- /dev/null +++ b/libjava/classpath/gnu/java/security/prng/LimitReachedException.java @@ -0,0 +1,57 @@ +/* LimitReachedException.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.prng; + +/** + * A checked exception that indicates that a pseudo random number generated has + * reached its theoretical limit in generating random bytes. + */ +public class LimitReachedException + extends Exception +{ + public LimitReachedException() + { + super(); + } + + public LimitReachedException(String msg) + { + super(msg); + } +} diff --git a/libjava/classpath/gnu/java/security/prng/MDGenerator.java b/libjava/classpath/gnu/java/security/prng/MDGenerator.java new file mode 100644 index 000000000..b110486f4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/prng/MDGenerator.java @@ -0,0 +1,127 @@ +/* MDGenerator.java -- + Copyright (C) 2001, 2002, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.prng; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; + +import java.util.Map; + +/** + * A simple pseudo-random number generator that relies on a hash algorithm, that + * (a) starts its operation by hashing a seed, and then (b) + * continuously re-hashing its output. If no hash algorithm name is specified in + * the {@link Map} of attributes used to initialise the instance then the + * SHA-160 algorithm is used as the underlying hash function. Also, if no + * seed is given, an empty octet sequence is used. + */ +public class MDGenerator + extends BasePRNG + implements Cloneable +{ + /** Property name of underlying hash algorithm for this generator. */ + public static final String MD_NAME = "gnu.crypto.prng.md.hash.name"; + + /** Property name of seed material. */ + public static final String SEEED = "gnu.crypto.prng.md.seed"; + + /** The underlying hash instance. */ + private IMessageDigest md; + + /** Trivial 0-arguments constructor. */ + public MDGenerator() + { + super(Registry.MD_PRNG); + } + + public void setup(Map attributes) + { + // find out which hash to use + String underlyingMD = (String) attributes.get(MD_NAME); + if (underlyingMD == null) + { + if (md == null) + { // happy birthday + // ensure we have a reliable implementation of this hash + md = HashFactory.getInstance(Registry.SHA160_HASH); + } + else // a clone. reset it for reuse + md.reset(); + } + else // ensure we have a reliable implementation of this hash + md = HashFactory.getInstance(underlyingMD); + // get the seeed + byte[] seed = (byte[]) attributes.get(SEEED); + if (seed == null) + seed = new byte[0]; + + md.update(seed, 0, seed.length); + } + + public void fillBlock() throws LimitReachedException + { + IMessageDigest mdc = (IMessageDigest) md.clone(); + buffer = mdc.digest(); + md.update(buffer, 0, buffer.length); + } + + public void addRandomByte(final byte b) + { + if (md == null) + throw new IllegalStateException("not initialized"); + md.update(b); + } + + public void addRandomBytes(final byte[] buf, final int off, final int len) + { + if (md == null) + throw new IllegalStateException("not initialized"); + md.update(buf, off, len); + } + + public Object clone() throws CloneNotSupportedException + { + MDGenerator result = (MDGenerator) super.clone(); + if (this.md != null) + result.md = (IMessageDigest) this.md.clone(); + + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/prng/PRNGFactory.java b/libjava/classpath/gnu/java/security/prng/PRNGFactory.java new file mode 100644 index 000000000..b57d7c7bb --- /dev/null +++ b/libjava/classpath/gnu/java/security/prng/PRNGFactory.java @@ -0,0 +1,92 @@ +/* PRNGFactory.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.prng; + +import gnu.java.security.Registry; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +/** + * A Factory to instantiate pseudo random number generators. + */ +public class PRNGFactory + implements Registry +{ + /** Trivial constructor to enforce Singleton pattern. */ + protected PRNGFactory() + { + } + + /** + * Returns an instance of a padding algorithm given its name. + * + * @param prng the case-insensitive name of the PRNG. + * @return an instance of the pseudo-random number generator. + * @exception InternalError if the implementation does not pass its self- + * test. + */ + public static final IRandom getInstance(String prng) + { + if (prng == null) + return null; + + prng = prng.trim(); + IRandom result = null; + if (prng.equalsIgnoreCase(MD_PRNG)) + result = new MDGenerator(); + + return result; + } + + /** + * Returns a {@link Set} of names of padding algorithms supported by this + * Factory. + * + * @return a {@link Set} of pseudo-random number generator algorithm names + * (Strings). + */ + public static final Set getNames() + { + HashSet hs = new HashSet(); + hs.add(MD_PRNG); + return Collections.unmodifiableSet(hs); + } +} diff --git a/libjava/classpath/gnu/java/security/prng/RandomEvent.java b/libjava/classpath/gnu/java/security/prng/RandomEvent.java new file mode 100644 index 000000000..fc4607a8a --- /dev/null +++ b/libjava/classpath/gnu/java/security/prng/RandomEvent.java @@ -0,0 +1,81 @@ +/* RandomEvent.java -- an event with random data. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.prng; + +import java.util.EventObject; + +/** + * A type for entropy accumulators that will be notified of random events. + */ +public class RandomEvent + extends EventObject +{ + private final byte sourceNumber; + + private final byte poolNumber; + + private final byte[] data; + + public RandomEvent(Object source, byte sourceNumber, byte poolNumber, + byte[] data) + { + super(source); + this.sourceNumber = sourceNumber; + this.poolNumber = poolNumber; + if (data.length == 0 || data.length > 32) + throw new IllegalArgumentException( + "random events take between 1 and 32 bytes of data"); + this.data = (byte[]) data.clone(); + } + + public byte getSourceNumber() + { + return sourceNumber; + } + + public byte getPoolNumber() + { + return poolNumber; + } + + public byte[] getData() + { + return data; + } +} diff --git a/libjava/classpath/gnu/java/security/prng/RandomEventListener.java b/libjava/classpath/gnu/java/security/prng/RandomEventListener.java new file mode 100644 index 000000000..720f2afe4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/prng/RandomEventListener.java @@ -0,0 +1,50 @@ +/* RandomEventListener.java -- + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.prng; + +import java.util.EventListener; + +/** + * An interface for entropy accumulators that will be notified of random events. + */ +public interface RandomEventListener + extends EventListener +{ + void addRandomEvent(RandomEvent event); +} diff --git a/libjava/classpath/gnu/java/security/provider/CollectionCertStoreImpl.java b/libjava/classpath/gnu/java/security/provider/CollectionCertStoreImpl.java new file mode 100644 index 000000000..4bf3d5434 --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/CollectionCertStoreImpl.java @@ -0,0 +1,102 @@ +/* CollectionCertStore.java -- Collection-based cert store. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import java.security.InvalidAlgorithmParameterException; +import java.security.cert.CRL; +import java.security.cert.CRLSelector; +import java.security.cert.CertSelector; +import java.security.cert.CertStoreException; +import java.security.cert.CertStoreParameters; +import java.security.cert.CertStoreSpi; +import java.security.cert.Certificate; +import java.security.cert.CollectionCertStoreParameters; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; + +public final class CollectionCertStoreImpl extends CertStoreSpi +{ + + // Fields. + // ------------------------------------------------------------------------- + + private final Collection store; + + // Constructors. + // ------------------------------------------------------------------------- + + public CollectionCertStoreImpl(CertStoreParameters params) + throws InvalidAlgorithmParameterException + { + super(params); + if (! (params instanceof CollectionCertStoreParameters)) + throw new InvalidAlgorithmParameterException("not a CollectionCertStoreParameters object"); + store = ((CollectionCertStoreParameters) params).getCollection(); + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public Collection engineGetCertificates(CertSelector selector) + throws CertStoreException + { + LinkedList result = new LinkedList(); + for (Iterator it = store.iterator(); it.hasNext(); ) + { + Object o = it.next(); + if ((o instanceof Certificate) && selector.match((Certificate) o)) + result.add(o); + } + return result; + } + + public Collection engineGetCRLs(CRLSelector selector) + throws CertStoreException + { + LinkedList result = new LinkedList(); + for (Iterator it = store.iterator(); it.hasNext(); ) + { + Object o = it.next(); + if ((o instanceof CRL) && selector.match((CRL) o)) + result.add(o); + } + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/provider/DefaultPolicy.java b/libjava/classpath/gnu/java/security/provider/DefaultPolicy.java new file mode 100644 index 000000000..566c949da --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/DefaultPolicy.java @@ -0,0 +1,68 @@ +/* DefaultPolicy.java -- + Copyright (C) 2001, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.security.provider; + +import java.security.AllPermission; +import java.security.CodeSource; +import java.security.Permission; +import java.security.PermissionCollection; +import java.security.Permissions; +import java.security.Policy; + +/** + * This is just a stub policy implementation which grants all permissions + * to any code source. FIXME: This should be replaced with a real + * implementation that reads the policy configuration from a file, like + * $JAVA_HOME/jre/lib/security/java.security. + */ +public class DefaultPolicy extends Policy +{ + static Permission allPermission = new AllPermission(); + + public PermissionCollection getPermissions(CodeSource codesource) + { + Permissions perms = new Permissions(); + perms.add(allPermission); + return perms; + } + + public void refresh() + { + // Nothing. + } +} diff --git a/libjava/classpath/gnu/java/security/provider/Gnu.java b/libjava/classpath/gnu/java/security/provider/Gnu.java new file mode 100644 index 000000000..62bb0a29e --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/Gnu.java @@ -0,0 +1,306 @@ +/* Gnu.java --- Gnu provider main class + Copyright (C) 1999, 2002, 2003, 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import java.security.AccessController; +import java.security.PrivilegedAction; +import java.security.Provider; + +public final class Gnu + extends Provider +{ + public Gnu() + { + super("GNU", 1.0, + "GNU provider v1.0 implementing SHA-1, MD5, DSA, RSA, X.509 " + + "Certificates and CRLs, PKIX certificate path validators, " + + "Collection cert stores, Diffie-Hellman key agreement and " + + "key pair generator"); + AccessController.doPrivileged (new PrivilegedAction() + { + public Object run() + { + // Note that all implementation class names are referenced by using + // Class.getName(). That way when we staticly link the Gnu provider + // we automatically get all the implementation classes. + + // Signature + put("Signature.SHA160withDSS", + gnu.java.security.jce.sig.SHA160withDSS.class.getName()); + put("Alg.Alias.Signature.SHA1withDSA", "SHA160withDSS"); + put("Alg.Alias.Signature.DSS", "SHA160withDSS"); + put("Alg.Alias.Signature.DSA", "SHA160withDSS"); + put("Alg.Alias.Signature.SHAwithDSA", "SHA160withDSS"); + put("Alg.Alias.Signature.DSAwithSHA", "SHA160withDSS"); + put("Alg.Alias.Signature.DSAwithSHA1", "SHA160withDSS"); + put("Alg.Alias.Signature.SHA/DSA", "SHA160withDSS"); + put("Alg.Alias.Signature.SHA-1/DSA", "SHA160withDSS"); + put("Alg.Alias.Signature.SHA1/DSA", "SHA160withDSS"); + put("Alg.Alias.Signature.OID.1.2.840.10040.4.3", "SHA160withDSS"); + put("Alg.Alias.Signature.1.2.840.10040.4.3", "SHA160withDSS"); + put("Alg.Alias.Signature.1.3.14.3.2.13", "SHA160withDSS"); + put("Alg.Alias.Signature.1.3.14.3.2.27", "SHA160withDSS"); + + put("Signature.MD2withRSA", + gnu.java.security.jce.sig.MD2withRSA.class.getName()); + put("Signature.MD2withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.md2WithRSAEncryption", "MD2withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.2", "MD2withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.2", "MD2withRSA"); + + put("Signature.MD5withRSA", + gnu.java.security.jce.sig.MD5withRSA.class.getName()); + put("Signature.MD5withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.md5WithRSAEncryption", "MD5withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.4", "MD5withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA"); + put("Alg.Alias.Signature.RSA", "MD5withRSA"); + + put("Signature.SHA160withRSA", + gnu.java.security.jce.sig.SHA160withRSA.class.getName()); + put("Signature.SHA160withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.sha-1WithRSAEncryption", "SHA160withRSA"); + put("Alg.Alias.Signature.sha-160WithRSAEncryption", "SHA160withRSA"); + put("Alg.Alias.Signature.sha1WithRSAEncryption", "SHA160withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.5", "SHA160withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA160withRSA"); + put("Alg.Alias.Signature.SHA1withRSA", "SHA160withRSA"); + + put("Signature.SHA256withRSA", + gnu.java.security.jce.sig.SHA256withRSA.class.getName()); + put("Signature.SHA160withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.sha256WithRSAEncryption", "SHA256withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.11", "SHA256withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA"); + + put("Signature.SHA384withRSA", + gnu.java.security.jce.sig.SHA384withRSA.class.getName()); + put("Signature.SHA160withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.sha384WithRSAEncryption", "SHA384withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.12", "SHA384withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA"); + + put("Signature.SHA512withRSA", + gnu.java.security.jce.sig.SHA512withRSA.class.getName()); + put("Signature.SHA160withRSA ImplementedIn", "Software"); + put("Alg.Alias.Signature.sha512WithRSAEncryption", "SHA512withRSA"); + put("Alg.Alias.Signature.OID.1.2.840.113549.1.1.13", "SHA512withRSA"); + put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA"); + + put("Signature.DSS/RAW", + gnu.java.security.jce.sig.DSSRawSignatureSpi.class.getName()); + put("Signature.DSS/RAW KeySize", "1024"); + put("Signature.DSS/RAW ImplementedIn", "Software"); + + put("Signature.RSA-PSS/RAW", + gnu.java.security.jce.sig.RSAPSSRawSignatureSpi.class.getName()); + put("Signature.RSA-PSS/RAW KeySize", "1024"); + put("Signature.RSA-PSS/RAW ImplementedIn", "Software"); + + // Key Pair Generator + put("KeyPairGenerator.DSS", + gnu.java.security.jce.sig.DSSKeyPairGeneratorSpi.class.getName()); + put("KeyPairGenerator.DSS KeySize", "1024"); + put("KeyPairGenerator.DSS ImplementedIn", "Software"); + put("Alg.Alias.KeyPairGenerator.DSA", "DSS"); + put("Alg.Alias.KeyPairGenerator.OID.1.2.840.10040.4.1", "DSS"); + put("Alg.Alias.KeyPairGenerator.1.2.840.10040.4.1", "DSS"); + put("Alg.Alias.KeyPairGenerator.1.3.14.3.2.12", "DSS"); + + put("KeyPairGenerator.RSA", + gnu.java.security.jce.sig.RSAKeyPairGeneratorSpi.class.getName()); + put("KeyPairGenerator.RSA KeySize", "1024"); + put("KeyPairGenerator.RSA ImplementedIn", "Software"); + + // Key Factory + put("KeyFactory.DSS", + gnu.java.security.jce.sig.DSSKeyFactory.class.getName()); + put("Alg.Alias.KeyFactory.DSA", "DSS"); + put("Alg.Alias.KeyFactory.OID.1.2.840.10040.4.1", "DSS"); + put("Alg.Alias.KeyFactory.1.2.840.10040.4.1", "DSS"); + put("Alg.Alias.KeyFactory.1.3.14.3.2.12", "DSS"); + + put("KeyFactory.RSA", + gnu.java.security.jce.sig.RSAKeyFactory.class.getName()); + + put("KeyFactory.Encoded", + gnu.java.security.jce.sig.EncodedKeyFactory.class.getName()); + put("KeyFactory.Encoded ImplementedIn", "Software"); + put("Alg.Alias.KeyFactory.X.509", "Encoded"); + put("Alg.Alias.KeyFactory.X509", "Encoded"); + put("Alg.Alias.KeyFactory.PKCS#8", "Encoded"); + put("Alg.Alias.KeyFactory.PKCS8", "Encoded"); + + put("MessageDigest.HAVAL", + gnu.java.security.jce.hash.HavalSpi.class.getName()); + put("MessageDigest.HAVAL ImplementedIn", "Software"); + put("MessageDigest.MD2", + gnu.java.security.jce.hash.MD2Spi.class.getName()); + put("MessageDigest.MD2 ImplementedIn", "Software"); + put("MessageDigest.MD4", + gnu.java.security.jce.hash.MD4Spi.class.getName()); + put("MessageDigest.MD4 ImplementedIn", "Software"); + put("MessageDigest.MD5", + gnu.java.security.jce.hash.MD5Spi.class.getName()); + put("MessageDigest.MD5 ImplementedIn", "Software"); + put("MessageDigest.RIPEMD128", + gnu.java.security.jce.hash.RipeMD128Spi.class.getName()); + put("MessageDigest.RIPEMD128 ImplementedIn", "Software"); + put("MessageDigest.RIPEMD160", + gnu.java.security.jce.hash.RipeMD160Spi.class.getName()); + put("MessageDigest.RIPEMD160 ImplementedIn", "Software"); + put("MessageDigest.SHA-160", + gnu.java.security.jce.hash.Sha160Spi.class.getName()); + put("MessageDigest.SHA-160 ImplementedIn", "Software"); + put("MessageDigest.SHA-256", + gnu.java.security.jce.hash.Sha256Spi.class.getName()); + put("MessageDigest.SHA-256 ImplementedIn", "Software"); + put("MessageDigest.SHA-384", + gnu.java.security.jce.hash.Sha384Spi.class.getName()); + put("MessageDigest.SHA-384 ImplementedIn", "Software"); + put("MessageDigest.SHA-512", + gnu.java.security.jce.hash.Sha512Spi.class.getName()); + put("MessageDigest.SHA-512 ImplementedIn", "Software"); + put("MessageDigest.TIGER", + gnu.java.security.jce.hash.TigerSpi.class.getName()); + put("MessageDigest.TIGER ImplementedIn", "Software"); + put("MessageDigest.WHIRLPOOL", + gnu.java.security.jce.hash.WhirlpoolSpi.class.getName()); + put("MessageDigest.WHIRLPOOL ImplementedIn", "Software"); + + put("Alg.Alias.MessageDigest.SHS", "SHA-160"); + put("Alg.Alias.MessageDigest.SHA", "SHA-160"); + put("Alg.Alias.MessageDigest.SHA1", "SHA-160"); + put("Alg.Alias.MessageDigest.SHA-1", "SHA-160"); + put("Alg.Alias.MessageDigest.SHA2-256", "SHA-256"); + put("Alg.Alias.MessageDigest.SHA2-384", "SHA-384"); + put("Alg.Alias.MessageDigest.SHA2-512", "SHA-512"); + put("Alg.Alias.MessageDigest.SHA256", "SHA-256"); + put("Alg.Alias.MessageDigest.SHA384", "SHA-384"); + put("Alg.Alias.MessageDigest.SHA512", "SHA-512"); + put("Alg.Alias.MessageDigest.RIPEMD-160", "RIPEMD160"); + put("Alg.Alias.MessageDigest.RIPEMD-128", "RIPEMD128"); + put("Alg.Alias.MessageDigest.OID.1.2.840.11359.2.2", "MD2"); + put("Alg.Alias.MessageDigest.1.2.840.11359.2.2", "MD2"); + put("Alg.Alias.MessageDigest.OID.1.2.840.11359.2.5", "MD5"); + put("Alg.Alias.MessageDigest.1.2.840.11359.2.5", "MD5"); + put("Alg.Alias.MessageDigest.OID.1.3.14.3.2.26", "SHA1"); + put("Alg.Alias.MessageDigest.1.3.14.3.2.26", "SHA1"); + + // Algorithm Parameters + put("AlgorithmParameters.DSS", + gnu.java.security.jce.sig.DSSParameters.class.getName()); + put("Alg.Alias.AlgorithmParameters.DSA", "DSS"); + put("Alg.Alias.AlgorithmParameters.SHAwithDSA", "DSS"); + put("Alg.Alias.AlgorithmParameters.OID.1.2.840.10040.4.3", "DSS"); + put("Alg.Alias.AlgorithmParameters.1.2.840.10040.4.3", "DSS"); + + // Algorithm Parameter Generator + put("AlgorithmParameterGenerator.DSA", + gnu.java.security.jce.sig.DSSParametersGenerator.class.getName()); + put("Alg.Alias.AlgorithmParameterGenerator.DSA", "DSS"); + + // SecureRandom + put("SecureRandom.SHA1PRNG", + gnu.java.security.jce.prng.Sha160RandomSpi.class.getName()); + + put("SecureRandom.MD2PRNG", + gnu.java.security.jce.prng.MD2RandomSpi.class.getName()); + put("SecureRandom.MD2PRNG ImplementedIn", "Software"); + put("SecureRandom.MD4PRNG", + gnu.java.security.jce.prng.MD4RandomSpi.class.getName()); + put("SecureRandom.MD4PRNG ImplementedIn", "Software"); + put("SecureRandom.MD5PRNG", + gnu.java.security.jce.prng.MD5RandomSpi.class.getName()); + put("SecureRandom.MD5PRNG ImplementedIn", "Software"); + put("SecureRandom.RIPEMD128PRNG", + gnu.java.security.jce.prng.RipeMD128RandomSpi.class.getName()); + put("SecureRandom.RIPEMD128PRNG ImplementedIn", "Software"); + put("SecureRandom.RIPEMD160PRNG", + gnu.java.security.jce.prng.RipeMD160RandomSpi.class.getName()); + put("SecureRandom.RIPEMD160PRNG ImplementedIn", "Software"); + put("SecureRandom.SHA-160PRNG", + gnu.java.security.jce.prng.Sha160RandomSpi.class.getName()); + put("SecureRandom.SHA-160PRNG ImplementedIn", "Software"); + put("SecureRandom.SHA-256PRNG", + gnu.java.security.jce.prng.Sha256RandomSpi.class.getName()); + put("SecureRandom.SHA-256PRNG ImplementedIn", "Software"); + put("SecureRandom.SHA-384PRNG", + gnu.java.security.jce.prng.Sha384RandomSpi.class.getName()); + put("SecureRandom.SHA-384PRNG ImplementedIn", "Software"); + put("SecureRandom.SHA-512PRNG", + gnu.java.security.jce.prng.Sha512RandomSpi.class.getName()); + put("SecureRandom.SHA-512PRNG ImplementedIn", "Software"); + put("SecureRandom.TIGERPRNG", + gnu.java.security.jce.prng.TigerRandomSpi.class.getName()); + put("SecureRandom.TIGERPRNG ImplementedIn", "Software"); + put("SecureRandom.HAVALPRNG", + gnu.java.security.jce.prng.HavalRandomSpi.class.getName()); + put("SecureRandom.HAVALPRNG ImplementedIn", "Software"); + put("SecureRandom.WHIRLPOOLPRNG", + gnu.java.security.jce.prng.WhirlpoolRandomSpi.class.getName()); + put("SecureRandom.WHIRLPOOLPRNG ImplementedIn", "Software"); + + put("Alg.Alias.SecureRandom.SHA-1PRNG", "SHA-160PRNG"); + put("Alg.Alias.SecureRandom.SHA1PRNG", "SHA-160PRNG"); + put("Alg.Alias.SecureRandom.SHAPRNG", "SHA-160PRNG"); + put("Alg.Alias.SecureRandom.SHA-256PRNG", "SHA-256PRNG"); + put("Alg.Alias.SecureRandom.SHA-2-1PRNG", "SHA-256PRNG"); + put("Alg.Alias.SecureRandom.SHA-384PRNG", "SHA-384PRNG"); + put("Alg.Alias.SecureRandom.SHA-2-2PRNG", "SHA-384PRNG"); + put("Alg.Alias.SecureRandom.SHA-512PRNG", "SHA-512PRNG"); + put("Alg.Alias.SecureRandom.SHA-2-3PRNG", "SHA-512PRNG"); + + // CertificateFactory + put("CertificateFactory.X509", X509CertificateFactory.class.getName()); + put("CertificateFactory.X509 ImplementedIn", "Software"); + put("Alg.Alias.CertificateFactory.X.509", "X509"); + + // CertPathValidator + put("CertPathValidator.PKIX", PKIXCertPathValidatorImpl.class.getName()); + put("CertPathValidator.PKIX ImplementedIn", "Software"); + + // CertStore + put("CertStore.Collection", CollectionCertStoreImpl.class.getName()); + + return null; + } + }); + } +} diff --git a/libjava/classpath/gnu/java/security/provider/PKIXCertPathValidatorImpl.java b/libjava/classpath/gnu/java/security/provider/PKIXCertPathValidatorImpl.java new file mode 100644 index 000000000..d4ce4aeb4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/PKIXCertPathValidatorImpl.java @@ -0,0 +1,693 @@ +/* PKIXCertPathValidatorImpl.java -- PKIX certificate path validator. + Copyright (C) 2004, 2005, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import gnu.java.security.Configuration; +import gnu.java.security.OID; +import gnu.java.security.Registry; +import gnu.java.security.key.dss.DSSPublicKey; +import gnu.java.security.x509.GnuPKIExtension; +import gnu.java.security.x509.PolicyNodeImpl; +import gnu.java.security.x509.X509CRLSelectorImpl; +import gnu.java.security.x509.X509CertSelectorImpl; +import gnu.java.security.x509.ext.BasicConstraints; +import gnu.java.security.x509.ext.CertificatePolicies; +import gnu.java.security.x509.ext.Extension; +import gnu.java.security.x509.ext.KeyUsage; +import gnu.java.security.x509.ext.PolicyConstraint; + +import java.io.IOException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.PublicKey; +import java.security.cert.CRL; +import java.security.cert.CertPath; +import java.security.cert.CertPathParameters; +import java.security.cert.CertPathValidatorException; +import java.security.cert.CertPathValidatorResult; +import java.security.cert.CertPathValidatorSpi; +import java.security.cert.CertStore; +import java.security.cert.CertStoreException; +import java.security.cert.CertificateException; +import java.security.cert.PKIXCertPathChecker; +import java.security.cert.PKIXCertPathValidatorResult; +import java.security.cert.PKIXParameters; +import java.security.cert.TrustAnchor; +import java.security.cert.X509CRL; +import java.security.cert.X509Certificate; +import java.security.interfaces.DSAParams; +import java.security.interfaces.DSAPublicKey; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashSet; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.logging.Logger; + +/** + * An implementation of the Public Key Infrastructure's X.509 certificate path + * validation algorithm. + *

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

+ * The CRL is accepted iff: + *

    + *
  1. The nextUpdate field (if present) is in the future.
  2. + *
  3. The CRL does not contain any unsupported critical extensions.
  4. + *
  5. The CRL is signed by one of the certificates in the path, or,
  6. + *
  7. The CRL is signed by the given public key and was issued by the public + * key's subject, or,
  8. + *
  9. The CRL is signed by a certificate in the given cert stores, and that + * cert is signed by one of the certificates in the path.
  10. + *
+ * + * @param crl The CRL being checked. + * @param path The path this CRL is being checked against. + * @param now The value to use as 'now'. + * @param pubKeyCert The certificate authenticating the public key. + * @param pubKey The public key to check. + * @return True if the CRL is acceptable. + */ + private static boolean checkCRL(X509CRL crl, X509Certificate[] path, + Date now, X509Certificate pubKeyCert, + PublicKey pubKey, List certStores) + { + Date nextUpdate = crl.getNextUpdate(); + if (nextUpdate != null && nextUpdate.compareTo(now) < 0) + return false; + if (crl.hasUnsupportedCriticalExtension()) + return false; + for (int i = 0; i < path.length; i++) + { + if (! path[i].getSubjectDN().equals(crl.getIssuerDN())) + continue; + boolean[] keyUsage = path[i].getKeyUsage(); + if (keyUsage != null) + { + if (! keyUsage[KeyUsage.CRL_SIGN]) + continue; + } + try + { + crl.verify(path[i].getPublicKey()); + return true; + } + catch (Exception x) + { + } + } + if (crl.getIssuerDN().equals(pubKeyCert.getSubjectDN())) + { + try + { + boolean[] keyUsage = pubKeyCert.getKeyUsage(); + if (keyUsage != null) + { + if (! keyUsage[KeyUsage.CRL_SIGN]) + throw new Exception(); + } + crl.verify(pubKey); + return true; + } + catch (Exception x) + { + } + } + try + { + X509CertSelectorImpl select = new X509CertSelectorImpl(); + select.addSubjectName(crl.getIssuerDN()); + List certs = new LinkedList(); + for (Iterator it = certStores.iterator(); it.hasNext();) + { + CertStore cs = (CertStore) it.next(); + try + { + certs.addAll(cs.getCertificates(select)); + } + catch (CertStoreException cse) + { + } + } + for (Iterator it = certs.iterator(); it.hasNext();) + { + X509Certificate c = (X509Certificate) it.next(); + for (int i = 0; i < path.length; i++) + { + if (! c.getIssuerDN().equals(path[i].getSubjectDN())) + continue; + boolean[] keyUsage = c.getKeyUsage(); + if (keyUsage != null) + { + if (! keyUsage[KeyUsage.CRL_SIGN]) + continue; + } + try + { + c.verify(path[i].getPublicKey()); + crl.verify(c.getPublicKey()); + return true; + } + catch (Exception x) + { + } + } + if (c.getIssuerDN().equals(pubKeyCert.getSubjectDN())) + { + c.verify(pubKey); + crl.verify(c.getPublicKey()); + } + } + } + catch (Exception x) + { + } + return false; + } + + private static Set getCritExts(X509Certificate cert) + { + HashSet s = new HashSet(); + if (cert instanceof GnuPKIExtension) + { + Collection exts = ((GnuPKIExtension) cert).getExtensions(); + for (Iterator it = exts.iterator(); it.hasNext();) + { + Extension ext = (Extension) it.next(); + if (ext.isCritical() && ! ext.isSupported()) + s.add(ext.getOid().toString()); + } + } + else + s.addAll(cert.getCriticalExtensionOIDs()); + return s; + } + + /** + * Perform a basic sanity check on the CA certificate at index. + */ + private static void basicSanity(X509Certificate[] path, int index) + throws CertPathValidatorException + { + X509Certificate cert = path[index]; + int pathLen = 0; + for (int i = index - 1; i > 0; i--) + { + if (! path[i].getIssuerDN().equals(path[i].getSubjectDN())) + pathLen++; + } + Extension e = null; + if (cert instanceof GnuPKIExtension) + { + e = ((GnuPKIExtension) cert).getExtension(BasicConstraints.ID); + } + else + { + try + { + e = new Extension(cert.getExtensionValue(BasicConstraints.ID.toString())); + } + catch (Exception x) + { + } + } + if (e == null) + throw new CertPathValidatorException("no basicConstraints"); + BasicConstraints bc = (BasicConstraints) e.getValue(); + if (! bc.isCA()) + throw new CertPathValidatorException( + "certificate cannot be used to verify signatures"); + if (bc.getPathLengthConstraint() >= 0 + && bc.getPathLengthConstraint() < pathLen) + throw new CertPathValidatorException("path is too long"); + + boolean[] keyUsage = cert.getKeyUsage(); + if (keyUsage != null) + { + if (! keyUsage[KeyUsage.KEY_CERT_SIGN]) + throw new CertPathValidatorException( + "certificate cannot be used to sign certificates"); + } + } + + private static void updatePolicyTree(X509Certificate cert, + PolicyNodeImpl root, int depth, + PKIXParameters params, + boolean explicitPolicy) + throws CertPathValidatorException + { + if (Configuration.DEBUG) + log.fine("updatePolicyTree depth == " + depth); + Set nodes = new HashSet(); + LinkedList stack = new LinkedList(); + Iterator current = null; + stack.addLast(Collections.singleton(root).iterator()); + do + { + current = (Iterator) stack.removeLast(); + while (current.hasNext()) + { + PolicyNodeImpl p = (PolicyNodeImpl) current.next(); + if (Configuration.DEBUG) + log.fine("visiting node == " + p); + if (p.getDepth() == depth - 1) + { + if (Configuration.DEBUG) + log.fine("added node"); + nodes.add(p); + } + else + { + if (Configuration.DEBUG) + log.fine("skipped node"); + stack.addLast(current); + current = p.getChildren(); + } + } + } + while (! stack.isEmpty()); + + Extension e = null; + CertificatePolicies policies = null; + List qualifierInfos = null; + if (cert instanceof GnuPKIExtension) + { + e = ((GnuPKIExtension) cert).getExtension(CertificatePolicies.ID); + if (e != null) + policies = (CertificatePolicies) e.getValue(); + } + + List cp = null; + if (policies != null) + cp = policies.getPolicies(); + else + cp = Collections.EMPTY_LIST; + boolean match = false; + if (Configuration.DEBUG) + { + log.fine("nodes are == " + nodes); + log.fine("cert policies are == " + cp); + } + for (Iterator it = nodes.iterator(); it.hasNext();) + { + PolicyNodeImpl parent = (PolicyNodeImpl) it.next(); + if (Configuration.DEBUG) + log.fine("adding policies to " + parent); + for (Iterator it2 = cp.iterator(); it2.hasNext();) + { + OID policy = (OID) it2.next(); + if (Configuration.DEBUG) + log.fine("trying to add policy == " + policy); + if (policy.toString().equals(ANY_POLICY) + && params.isAnyPolicyInhibited()) + continue; + PolicyNodeImpl child = new PolicyNodeImpl(); + child.setValidPolicy(policy.toString()); + child.addExpectedPolicy(policy.toString()); + if (parent.getExpectedPolicies().contains(policy.toString())) + { + parent.addChild(child); + match = true; + } + else if (parent.getExpectedPolicies().contains(ANY_POLICY)) + { + parent.addChild(child); + match = true; + } + else if (ANY_POLICY.equals(policy.toString())) + { + parent.addChild(child); + match = true; + } + if (match && policies != null) + { + List qualifiers = policies.getPolicyQualifierInfos(policy); + if (qualifiers != null) + child.addAllPolicyQualifiers(qualifiers); + } + } + } + if (! match && (params.isExplicitPolicyRequired() || explicitPolicy)) + throw new CertPathValidatorException("policy tree building failed"); + } + + private boolean checkExplicitPolicy(int depth, List explicitPolicies) + { + if (Configuration.DEBUG) + log.fine("checkExplicitPolicy depth=" + depth); + for (Iterator it = explicitPolicies.iterator(); it.hasNext();) + { + int[] i = (int[]) it.next(); + int caDepth = i[0]; + int limit = i[1]; + if (Configuration.DEBUG) + log.fine(" caDepth=" + caDepth + " limit=" + limit); + if (depth - caDepth >= limit) + return true; + } + return false; + } +} diff --git a/libjava/classpath/gnu/java/security/provider/X509CertificateFactory.java b/libjava/classpath/gnu/java/security/provider/X509CertificateFactory.java new file mode 100644 index 000000000..644033156 --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/X509CertificateFactory.java @@ -0,0 +1,295 @@ +/* X509CertificateFactory.java -- generates X.509 certificates. + Copyright (C) 2003 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.provider; + +import gnu.java.io.Base64InputStream; +import gnu.java.lang.CPStringBuilder; +import gnu.java.security.x509.X509CRL; +import gnu.java.security.x509.X509CertPath; +import gnu.java.security.x509.X509Certificate; + +import java.io.BufferedInputStream; +import java.io.EOFException; +import java.io.IOException; +import java.io.InputStream; +import java.security.cert.CRL; +import java.security.cert.CRLException; +import java.security.cert.CertPath; +import java.security.cert.Certificate; +import java.security.cert.CertificateEncodingException; +import java.security.cert.CertificateException; +import java.security.cert.CertificateFactorySpi; +import java.util.Collection; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +public class X509CertificateFactory + extends CertificateFactorySpi +{ + public static final String BEGIN_CERTIFICATE = "-----BEGIN CERTIFICATE-----"; + + public static final String END_CERTIFICATE = "-----END CERTIFICATE-----"; + + public static final String BEGIN_X509_CRL = "-----BEGIN X509 CRL-----"; + + public static final String END_X509_CRL = "-----END X509 CRL-----"; + + public X509CertificateFactory() + { + super(); + } + + public Certificate engineGenerateCertificate(InputStream inStream) + throws CertificateException + { + try + { + return generateCert(inStream); + } + catch (IOException ioe) + { + CertificateException ce = new CertificateException(ioe.getMessage()); + ce.initCause(ioe); + throw ce; + } + } + + public Collection engineGenerateCertificates(InputStream inStream) + throws CertificateException + { + LinkedList certs = new LinkedList(); + while (true) + { + try + { + certs.add(generateCert(inStream)); + } + catch (EOFException eof) + { + break; + } + catch (IOException ioe) + { + CertificateException ce = new CertificateException(ioe.getMessage()); + ce.initCause(ioe); + throw ce; + } + } + return certs; + } + + public CRL engineGenerateCRL(InputStream inStream) throws CRLException + { + try + { + return generateCRL(inStream); + } + catch (IOException ioe) + { + CRLException crle = new CRLException(ioe.getMessage()); + crle.initCause(ioe); + throw crle; + } + } + + public Collection engineGenerateCRLs(InputStream inStream) + throws CRLException + { + LinkedList crls = new LinkedList(); + while (true) + { + try + { + crls.add(generateCRL(inStream)); + } + catch (EOFException eof) + { + break; + } + catch (IOException ioe) + { + CRLException crle = new CRLException(ioe.getMessage()); + crle.initCause(ioe); + throw crle; + } + } + return crls; + } + + public CertPath engineGenerateCertPath(List certs) + { + return new X509CertPath(certs); + } + + public CertPath engineGenerateCertPath(InputStream in) + throws CertificateEncodingException + { + return new X509CertPath(in); + } + + public CertPath engineGenerateCertPath(InputStream in, String encoding) + throws CertificateEncodingException + { + return new X509CertPath(in, encoding); + } + + public Iterator engineGetCertPathEncodings() + { + return X509CertPath.ENCODINGS.iterator(); + } + + private X509Certificate generateCert(InputStream inStream) + throws IOException, CertificateException + { + if (inStream == null) + throw new CertificateException("missing input stream"); + if (! inStream.markSupported()) + inStream = new BufferedInputStream(inStream, 8192); + inStream.mark(20); + int i = inStream.read(); + if (i == -1) + throw new EOFException(); + // If the input is in binary DER format, the first byte MUST be + // 0x30, which stands for the ASN.1 [UNIVERSAL 16], which is the + // UNIVERSAL SEQUENCE, with the CONSTRUCTED bit (0x20) set. + // + // So if we do not see 0x30 here we will assume it is in Base-64. + if (i != 0x30) + { + inStream.reset(); + CPStringBuilder line = new CPStringBuilder(80); + do + { + line.setLength(0); + do + { + i = inStream.read(); + if (i == -1) + throw new EOFException(); + if (i != '\n' && i != '\r') + line.append((char) i); + } + while (i != '\n' && i != '\r'); + } + while (! line.toString().equals(BEGIN_CERTIFICATE)); + X509Certificate ret = new X509Certificate( + new BufferedInputStream(new Base64InputStream(inStream), 8192)); + line.setLength(0); + line.append('-'); // Base64InputStream will eat this. + do + { + i = inStream.read(); + if (i == -1) + throw new EOFException(); + if (i != '\n' && i != '\r') + line.append((char) i); + } + while (i != '\n' && i != '\r'); + // XXX ??? + if (! line.toString().equals(END_CERTIFICATE)) + throw new CertificateException("no end-of-certificate marker"); + return ret; + } + else + { + inStream.reset(); + return new X509Certificate(inStream); + } + } + + private X509CRL generateCRL(InputStream inStream) throws IOException, + CRLException + { + if (inStream == null) + throw new CRLException("missing input stream"); + if (! inStream.markSupported()) + inStream = new BufferedInputStream(inStream, 8192); + inStream.mark(20); + int i = inStream.read(); + if (i == -1) + throw new EOFException(); + // If the input is in binary DER format, the first byte MUST be + // 0x30, which stands for the ASN.1 [UNIVERSAL 16], which is the + // UNIVERSAL SEQUENCE, with the CONSTRUCTED bit (0x20) set. + // + // So if we do not see 0x30 here we will assume it is in Base-64. + if (i != 0x30) + { + inStream.reset(); + CPStringBuilder line = new CPStringBuilder(80); + do + { + line.setLength(0); + do + { + i = inStream.read(); + if (i == -1) + throw new EOFException(); + if (i != '\n' && i != '\r') + line.append((char) i); + } + while (i != '\n' && i != '\r'); + } + while (! line.toString().startsWith(BEGIN_X509_CRL)); + X509CRL ret = new X509CRL( + new BufferedInputStream(new Base64InputStream(inStream), 8192)); + line.setLength(0); + line.append('-'); // Base64InputStream will eat this. + do + { + i = inStream.read(); + if (i == -1) + throw new EOFException(); + if (i != '\n' && i != '\r') + line.append((char) i); + } + while (i != '\n' && i != '\r'); + // XXX ??? + if (! line.toString().startsWith(END_X509_CRL)) + throw new CRLException("no end-of-CRL marker"); + return ret; + } + else + { + inStream.reset(); + return new X509CRL(inStream); + } + } +} diff --git a/libjava/classpath/gnu/java/security/provider/package.html b/libjava/classpath/gnu/java/security/provider/package.html new file mode 100644 index 000000000..641a22aff --- /dev/null +++ b/libjava/classpath/gnu/java/security/provider/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security.provider + + +

+ + + diff --git a/libjava/classpath/gnu/java/security/sig/BaseSignature.java b/libjava/classpath/gnu/java/security/sig/BaseSignature.java new file mode 100644 index 000000000..ef4d87f26 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/BaseSignature.java @@ -0,0 +1,219 @@ +/* BaseSignature.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig; + +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.util.PRNG; + +import java.security.PrivateKey; +import java.security.PublicKey; +import java.util.Map; +import java.util.Random; + +/** + * A base abstract class to facilitate implementations of concrete Signatures. + */ +public abstract class BaseSignature + implements ISignature +{ + /** The canonical name of this signature scheme. */ + protected String schemeName; + + /** The underlying message digest instance for this signature scheme. */ + protected IMessageDigest md; + + /** The public key to use when verifying signatures. */ + protected PublicKey publicKey; + + /** The private key to use when generating signatures (signing). */ + protected PrivateKey privateKey; + + /** The optional {@link Random} instance to use. */ + private Random rnd; + + /** The optional {@link IRandom} instance to use. */ + private IRandom irnd; + + /** Our default source of randomness. */ + private PRNG prng = null; + + /** + * Trivial constructor. + * + * @param schemeName the name of this signature scheme. + * @param md the underlying instance of the message digest algorithm. + * @throws IllegalArgumentException if the designated hash instance is + * null. + */ + protected BaseSignature(String schemeName, IMessageDigest md) + { + super(); + + this.schemeName = schemeName; + if (md == null) + throw new IllegalArgumentException("Message digest MUST NOT be null"); + + this.md = md; + } + + public String name() + { + return schemeName + "-" + md.name(); + } + + public void setupVerify(Map attributes) throws IllegalArgumentException + { + setup(attributes); + // do we have a public key? + PublicKey key = (PublicKey) attributes.get(VERIFIER_KEY); + if (key != null) + setupForVerification(key); + } + + public void setupSign(Map attributes) throws IllegalArgumentException + { + setup(attributes); + // do we have a private key? + PrivateKey key = (PrivateKey) attributes.get(SIGNER_KEY); + if (key != null) + setupForSigning(key); + } + + public void update(byte b) + { + if (md == null) + throw new IllegalStateException(); + + md.update(b); + } + + public void update(byte[] b, int off, int len) + { + if (md == null) + throw new IllegalStateException(); + + md.update(b, off, len); + } + + public Object sign() + { + if (md == null || privateKey == null) + throw new IllegalStateException(); + + return generateSignature(); + } + + public boolean verify(Object sig) + { + if (md == null || publicKey == null) + throw new IllegalStateException(); + + return verifySignature(sig); + } + + public abstract Object clone(); + + protected abstract void setupForVerification(PublicKey key) + throws IllegalArgumentException; + + protected abstract void setupForSigning(PrivateKey key) + throws IllegalArgumentException; + + protected abstract Object generateSignature() throws IllegalStateException; + + protected abstract boolean verifySignature(Object signature) + throws IllegalStateException; + + /** Initialises the internal fields of this instance. */ + protected void init() + { + md.reset(); + rnd = null; + irnd = null; + publicKey = null; + privateKey = null; + } + + /** + * Fills the designated byte array with random data. + * + * @param buffer the byte array to fill with random data. + */ + protected void nextRandomBytes(byte[] buffer) + { + if (rnd != null) + rnd.nextBytes(buffer); + else if (irnd != null) + try + { + irnd.nextBytes(buffer, 0, buffer.length); + } + catch (IllegalStateException x) + { + throw new RuntimeException("nextRandomBytes(): " + x); + } + catch (LimitReachedException x) + { + throw new RuntimeException("nextRandomBytes(): " + x); + } + else + getDefaultPRNG().nextBytes(buffer); + } + + private void setup(Map attributes) + { + init(); + // do we have a Random or SecureRandom, or should we use our own? + Object obj = attributes.get(SOURCE_OF_RANDOMNESS); + if (obj instanceof Random) + rnd = (Random) obj; + else if (obj instanceof IRandom) + irnd = (IRandom) obj; + } + + private PRNG getDefaultPRNG() + { + if (prng == null) + prng = PRNG.getInstance(); + + return prng; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/ISignature.java b/libjava/classpath/gnu/java/security/sig/ISignature.java new file mode 100644 index 000000000..be98f9a9b --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/ISignature.java @@ -0,0 +1,160 @@ +/* ISignature.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig; + +import java.util.Map; + +/** + * The visible methods of every signature-with-appendix scheme. + *

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

+ * References: + *

    + *
  1. Handbook of Applied + * Cryptography, Alfred J. Menezes, Paul C. van Oorschot and Scott A. + * Vanstone. Section 11.2.2 Digital signature schemes with appendix.
  2. + *
+ */ +public interface ISignature + extends Cloneable +{ + /** Property name of the verifier's public key. */ + public static final String VERIFIER_KEY = "gnu.crypto.sig.public.key"; + + /** Property name of the signer's private key. */ + public static final String SIGNER_KEY = "gnu.crypto.sig.private.key"; + + /** + * Property name of an optional {@link java.security.SecureRandom}, + * {@link java.util.Random}, or {@link gnu.java.security.prng.IRandom} + * instance to use. The default is to use a classloader singleton from + * {@link gnu.java.security.util.PRNG}. + */ + public static final String SOURCE_OF_RANDOMNESS = "gnu.crypto.sig.prng"; + + /** + * Returns the canonical name of this signature scheme. + * + * @return the canonical name of this instance. + */ + String name(); + + /** + * Initialises this instance for signature verification. + * + * @param attributes the attributes to use for setting up this instance. + * @throws IllegalArgumentException if the designated public key is not + * appropriate for this signature scheme. + * @see #SOURCE_OF_RANDOMNESS + * @see #VERIFIER_KEY + */ + void setupVerify(Map attributes) throws IllegalArgumentException; + + /** + * Initialises this instance for signature generation. + * + * @param attributes the attributes to use for setting up this instance. + * @throws IllegalArgumentException if the designated private key is not + * appropriate for this signature scheme. + * @see #SOURCE_OF_RANDOMNESS + * @see #SIGNER_KEY + */ + void setupSign(Map attributes) throws IllegalArgumentException; + + /** + * Digests one byte of a message for signing or verification purposes. + * + * @param b the message byte to digest. + * @throws IllegalStateException if this instance was not setup for signature + * generation/verification. + */ + void update(byte b) throws IllegalStateException; + + /** + * Digests a sequence of bytes from a message for signing or verification + * purposes. + * + * @param buffer the byte sequence to consider. + * @param offset the byte poisition in buffer of the first byte + * to consider. + * @param length the number of bytes in buffer starting from + * the byte at index offset to digest. + * @throws IllegalStateException if this instance was not setup for signature + * generation/verification. + */ + void update(byte[] buffer, int offset, int length) + throws IllegalStateException; + + /** + * Terminates a signature generation phase by digesting and processing the + * context of the underlying message digest algorithm instance. + * + * @return a {@link Object} representing the native output of the signature + * scheme implementation. + * @throws IllegalStateException if this instance was not setup for signature + * generation. + */ + Object sign() throws IllegalStateException; + + /** + * Terminates a signature verification phase by digesting and processing the + * context of the underlying message digest algorithm instance. + * + * @param signature a native signature object previously generated by an + * invocation of the sign() method. + * @return true iff the outpout of the verification phase + * confirms that the designated signature object has been generated + * using the corresponding public key of the recepient. + * @throws IllegalStateException if this instance was not setup for signature + * verification. + */ + boolean verify(Object signature) throws IllegalStateException; + + /** + * Returns a clone copy of this instance. + * + * @return a clone copy of this instance. + */ + Object clone(); +} diff --git a/libjava/classpath/gnu/java/security/sig/ISignatureCodec.java b/libjava/classpath/gnu/java/security/sig/ISignatureCodec.java new file mode 100644 index 000000000..f8b147361 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/ISignatureCodec.java @@ -0,0 +1,59 @@ +/* ISignatureCodec.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig; + +import gnu.java.security.Registry; + +/** + * The visible methods of an object that knows how to encode and decode + * cryptographic signatures. Codecs are useful for (a) externalising signature + * output data for storage and on-the-wire transmission, as well as (b) re- + * creating their internal Java representation from external sources. + */ +public interface ISignatureCodec +{ + /** Constant identifying the Raw encoding format. */ + int RAW_FORMAT = Registry.RAW_ENCODING_ID; + + int getFormatID(); + + byte[] encodeSignature(Object signature); + + Object decodeSignature(byte[] input); +} diff --git a/libjava/classpath/gnu/java/security/sig/SignatureCodecFactory.java b/libjava/classpath/gnu/java/security/sig/SignatureCodecFactory.java new file mode 100644 index 000000000..0026ad164 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/SignatureCodecFactory.java @@ -0,0 +1,226 @@ +/* SignatureCodecFactory.java -- Factory to instantiate Signature codecs + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.sig.dss.DSSSignatureRawCodec; +import gnu.java.security.sig.dss.DSSSignatureX509Codec; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureRawCodec; +import gnu.java.security.sig.rsa.RSAPKCS1V1_5SignatureX509Codec; +import gnu.java.security.sig.rsa.RSAPSSSignatureRawCodec; +import gnu.java.security.util.FormatUtil; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +/** + * A Factory class to instantiate Signature codecs. + */ +public class SignatureCodecFactory +{ + private static Set names; + + /** Trivial constructor to enforce Singleton pattern. */ + private SignatureCodecFactory() + { + super(); + } + + /** + * Returns the appropriate codec given a composed signature algorithm and an + * encoding format. A composed name is formed by the concatenation of the + * canonical signature algorithm name, the forward slash character + * / and the canonical name of the encoding format. + *

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

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

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

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

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

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

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

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

+ * References: + *

    + *
  1. Digital Signature + * Standard (DSS), Federal Information Processing Standards Publication + * 186. National Institute of Standards and Technology.
  2. + *
+ */ +public class DSSSignature + extends BaseSignature +{ + /** Trivial 0-arguments constructor. */ + public DSSSignature() + { + super(Registry.DSS_SIG, new Sha160()); + } + + /** Private constructor for cloning purposes. */ + private DSSSignature(DSSSignature that) + { + this(); + + this.publicKey = that.publicKey; + this.privateKey = that.privateKey; + this.md = (IMessageDigest) that.md.clone(); + } + + public static final BigInteger[] sign(final DSAPrivateKey k, final byte[] h) + { + final DSSSignature sig = new DSSSignature(); + final Map attributes = new HashMap(); + attributes.put(ISignature.SIGNER_KEY, k); + sig.setupSign(attributes); + return sig.computeRS(h); + } + + public static final BigInteger[] sign(final DSAPrivateKey k, final byte[] h, + Random rnd) + { + final DSSSignature sig = new DSSSignature(); + final Map attributes = new HashMap(); + attributes.put(ISignature.SIGNER_KEY, k); + if (rnd != null) + attributes.put(ISignature.SOURCE_OF_RANDOMNESS, rnd); + + sig.setupSign(attributes); + return sig.computeRS(h); + } + + public static final BigInteger[] sign(final DSAPrivateKey k, final byte[] h, + IRandom irnd) + { + final DSSSignature sig = new DSSSignature(); + final Map attributes = new HashMap(); + attributes.put(ISignature.SIGNER_KEY, k); + if (irnd != null) + attributes.put(ISignature.SOURCE_OF_RANDOMNESS, irnd); + + sig.setupSign(attributes); + return sig.computeRS(h); + } + + public static final boolean verify(final DSAPublicKey k, final byte[] h, + final BigInteger[] rs) + { + final DSSSignature sig = new DSSSignature(); + final Map attributes = new HashMap(); + attributes.put(ISignature.VERIFIER_KEY, k); + sig.setupVerify(attributes); + return sig.checkRS(rs, h); + } + + public Object clone() + { + return new DSSSignature(this); + } + + protected void setupForVerification(PublicKey k) + throws IllegalArgumentException + { + if (! (k instanceof DSAPublicKey)) + throw new IllegalArgumentException(); + + this.publicKey = k; + } + + protected void setupForSigning(PrivateKey k) throws IllegalArgumentException + { + if (! (k instanceof DSAPrivateKey)) + throw new IllegalArgumentException(); + + this.privateKey = k; + } + + protected Object generateSignature() throws IllegalStateException + { + final BigInteger[] rs = computeRS(md.digest()); + return encodeSignature(rs[0], rs[1]); + } + + protected boolean verifySignature(Object sig) throws IllegalStateException + { + final BigInteger[] rs = decodeSignature(sig); + return checkRS(rs, md.digest()); + } + + /** + * Returns the output of a signature generation phase. + * + * @return an object encapsulating the DSS signature pair r and + * s. + */ + private Object encodeSignature(BigInteger r, BigInteger s) + { + return new BigInteger[] { r, s }; + } + + /** + * Returns the output of a previously generated signature object as a pair of + * {@link java.math.BigInteger}. + * + * @return the DSS signature pair r and s. + */ + private BigInteger[] decodeSignature(Object signature) + { + return (BigInteger[]) signature; + } + + private BigInteger[] computeRS(final byte[] digestBytes) + { + final BigInteger p = ((DSAPrivateKey) privateKey).getParams().getP(); + final BigInteger q = ((DSAPrivateKey) privateKey).getParams().getQ(); + final BigInteger g = ((DSAPrivateKey) privateKey).getParams().getG(); + final BigInteger x = ((DSAPrivateKey) privateKey).getX(); + final BigInteger m = new BigInteger(1, digestBytes); + BigInteger k, r, s; + final byte[] kb = new byte[20]; // we'll use 159 bits only + while (true) + { + this.nextRandomBytes(kb); + k = new BigInteger(1, kb); + k.clearBit(159); + r = g.modPow(k, p).mod(q); + if (r.equals(BigInteger.ZERO)) + continue; + + s = m.add(x.multiply(r)).multiply(k.modInverse(q)).mod(q); + if (s.equals(BigInteger.ZERO)) + continue; + + break; + } + return new BigInteger[] { r, s }; + } + + private boolean checkRS(final BigInteger[] rs, final byte[] digestBytes) + { + final BigInteger r = rs[0]; + final BigInteger s = rs[1]; + final BigInteger g = ((DSAPublicKey) publicKey).getParams().getG(); + final BigInteger p = ((DSAPublicKey) publicKey).getParams().getP(); + final BigInteger q = ((DSAPublicKey) publicKey).getParams().getQ(); + final BigInteger y = ((DSAPublicKey) publicKey).getY(); + final BigInteger w = s.modInverse(q); + final BigInteger u1 = w.multiply(new BigInteger(1, digestBytes)).mod(q); + final BigInteger u2 = r.multiply(w).mod(q); + final BigInteger v = g.modPow(u1, p).multiply(y.modPow(u2, p)).mod(p).mod(q); + return v.equals(r); + } +} diff --git a/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureRawCodec.java b/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureRawCodec.java new file mode 100644 index 000000000..169f84bd1 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/dss/DSSSignatureRawCodec.java @@ -0,0 +1,164 @@ +/* DSSSignatureRawCodec.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.dss; + +import gnu.java.security.Registry; +import gnu.java.security.sig.ISignatureCodec; + +import java.io.ByteArrayOutputStream; +import java.math.BigInteger; + +/** + * An object that implements the {@link ISignatureCodec} operations for the + * Raw format to use with DSS signatures. + */ +public class DSSSignatureRawCodec + implements ISignatureCodec +{ + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * Returns the encoded form of the designated DSS (Digital Signature Standard) + * signature object according to the Raw format supported by this + * library. + *

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

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

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

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

+ * The output of the encoder, and the input of the decoder, of this codec are + * then the raw bytes of such a BIT STRING; i.e. not the DER-encoded + * form itself. + *

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

+ *   Dss-Sig-Value ::= SEQUENCE {
+ *     r  INTEGER,
+ *     s  INTEGER
+ *   }
+ * 
+ *

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

+ *

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

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

+ * References: + *

    + *
  1. Public-Key Cryptography + * Standards (PKCS) #1:
    + * RSA Cryptography Specifications Version 2.1.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ */ +public class EME_PKCS1_V1_5 +{ + private int k; + + private ByteArrayOutputStream baos = new ByteArrayOutputStream(); + + /** Our default source of randomness. */ + private PRNG prng = PRNG.getInstance(); + + private EME_PKCS1_V1_5(final int k) + { + super(); + + this.k = k; + } + + public static final EME_PKCS1_V1_5 getInstance(final int k) + { + if (k < 0) + throw new IllegalArgumentException("k must be a positive integer"); + + return new EME_PKCS1_V1_5(k); + } + + public static final EME_PKCS1_V1_5 getInstance(final RSAKey key) + { + final int modBits = key.getModulus().bitLength(); + final int k = (modBits + 7) / 8; + return EME_PKCS1_V1_5.getInstance(k); + } + + /** + * Generates an octet string PS of length k - mLen - + * 3 consisting of pseudo-randomly generated nonzero octets. The length + * of PS will be at least eight octets. + *

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

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

+ * This method uses a default PRNG to obtain the padding bytes. + * + * @param M the message to encode. + * @return the encoded message EM. + */ + public byte[] encode(final byte[] M) + { + // a. Generate an octet string PS of length k - mLen - 3 consisting + // of pseudo-randomly generated nonzero octets. The length of PS + // will be at least eight octets. + final byte[] PS = new byte[k - M.length - 3]; + // FIXME. This should be configurable, somehow. + prng.nextBytes(PS); + int i = 0; + for (; i < PS.length; i++) + { + if (PS[i] == 0) + PS[i] = 1; + } + // b. Concatenate PS, the message M, and other padding to form an + // encoded message EM of length k octets as + // + // EM = 0x00 || 0x02 || PS || 0x00 || M. + return assembleEM(PS, M); + } + + /** + * Similar to {@link #encode(byte[])} method, except that the source of + * randomness to use for obtaining the padding bytes (an instance of + * {@link IRandom}) is given as a parameter. + * + * @param M the message to encode. + * @param irnd the {@link IRandom} instance to use as a source of randomness. + * @return the encoded message EM. + */ + public byte[] encode(final byte[] M, final IRandom irnd) + { + final byte[] PS = new byte[k - M.length - 3]; + try + { + irnd.nextBytes(PS, 0, PS.length); + int i = 0; + outer: while (true) + { + for (; i < PS.length; i++) + { + if (PS[i] == 0x00) + { + System.arraycopy(PS, i + 1, PS, i, PS.length - i - 1); + irnd.nextBytes(PS, PS.length - 1, 1); + continue outer; + } + } + break; + } + } + catch (IllegalStateException x) + { + throw new RuntimeException("encode(): " + String.valueOf(x)); + } + catch (LimitReachedException x) + { + throw new RuntimeException("encode(): " + String.valueOf(x)); + } + return assembleEM(PS, M); + } + + /** + * Similar to the {@link #encode(byte[], IRandom)} method, except that the + * source of randmoness is an instance of {@link Random}. + * + * @param M the message to encode. + * @param rnd the {@link Random} instance to use as a source of randomness. + * @return the encoded message EM. + */ + public byte[] encode(final byte[] M, final Random rnd) + { + final byte[] PS = new byte[k - M.length - 3]; + rnd.nextBytes(PS); + int i = 0; + outer: while (true) + { + for (; i < PS.length; i++) + { + if (PS[i] == 0x00) + { + System.arraycopy(PS, i + 1, PS, i, PS.length - i - 1); + PS[PS.length - 1] = (byte) rnd.nextInt(); + continue outer; + } + } + break; + } + return assembleEM(PS, M); + } + + /** + * Separate the encoded message EM into an octet string + * PS consisting of nonzero octets and a message M + * as: + *

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

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

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

+ * References: + *

    + *
  1. Public-Key Cryptography + * Standards (PKCS) #1:
    + * RSA Cryptography Specifications Version 2.1.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ */ +public class EMSA_PKCS1_V1_5 + implements Cloneable +{ + /* Notes. + 1. For the six hash functions mentioned in Appendix B.1, the DER encoding + T of the DigestInfo value is equal to the following: + + MD2: (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 02 05 00 04 10 || H + MD5: (0x)30 20 30 0c 06 08 2a 86 48 86 f7 0d 02 05 05 00 04 10 || H + SHA-1: (0x)30 21 30 09 06 05 2b 0e 03 02 1a 05 00 04 14 || H + SHA-256: (0x)30 31 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 04 20 || H + SHA-384: (0x)30 41 30 0d 06 09 60 86 48 01 65 03 04 02 02 05 00 04 30 || H + SHA-512: (0x)30 51 30 0d 06 09 60 86 48 01 65 03 04 02 03 05 00 04 40 || H + */ + private static final byte[] MD2_PREFIX = { + (byte) 0x30, (byte) 0x20, (byte) 0x30, (byte) 0x0c, (byte) 0x06, + (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, + (byte) 0xf7, (byte) 0x0d, (byte) 0x02, (byte) 0x02, (byte) 0x05, + (byte) 0x00, (byte) 0x04, (byte) 0x10 + }; + + private static final byte[] MD5_PREFIX = { + (byte) 0x30, (byte) 0x20, (byte) 0x30, (byte) 0x0c, (byte) 0x06, + (byte) 0x08, (byte) 0x2a, (byte) 0x86, (byte) 0x48, (byte) 0x86, + (byte) 0xf7, (byte) 0x0d, (byte) 0x02, (byte) 0x05, (byte) 0x05, + (byte) 0x00, (byte) 0x04, (byte) 0x10 + }; + + private static final byte[] SHA160_PREFIX = { + (byte) 0x30, (byte) 0x21, (byte) 0x30, (byte) 0x09, (byte) 0x06, + (byte) 0x05, (byte) 0x2b, (byte) 0x0e, (byte) 0x03, (byte) 0x02, + (byte) 0x1a, (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x14 + }; + + private static final byte[] SHA256_PREFIX = { + (byte) 0x30, (byte) 0x31, (byte) 0x30, (byte) 0x0d, (byte) 0x06, + (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01, + (byte) 0x65, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0x01, + (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x20 + }; + + private static final byte[] SHA384_PREFIX = { + (byte) 0x30, (byte) 0x41, (byte) 0x30, (byte) 0x0d, (byte) 0x06, + (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01, + (byte) 0x65, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0x02, + (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x30 + }; + + private static final byte[] SHA512_PREFIX = { + (byte) 0x30, (byte) 0x51, (byte) 0x30, (byte) 0x0d, (byte) 0x06, + (byte) 0x09, (byte) 0x60, (byte) 0x86, (byte) 0x48, (byte) 0x01, + (byte) 0x65, (byte) 0x03, (byte) 0x04, (byte) 0x02, (byte) 0x03, + (byte) 0x05, (byte) 0x00, (byte) 0x04, (byte) 0x40 + }; + + /** The underlying hash function to use with this instance. */ + private IMessageDigest hash; + + /** The output size of the hash function in octets. */ + private int hLen; // TODO: field not used!!! investigate + + /** The DER part of DigestInfo not containing the hash value itself. */ + private byte[] prefix; + + /** + * Trivial private constructor to enforce use through Factory method. + * + * @param hash the message digest instance to use with this scheme instance. + */ + private EMSA_PKCS1_V1_5(final IMessageDigest hash) + { + super(); + + this.hash = hash; + hLen = hash.hashSize(); + final String name = hash.name(); + if (name.equals(Registry.MD2_HASH)) + prefix = MD2_PREFIX; + else if (name.equals(Registry.MD5_HASH)) + prefix = MD5_PREFIX; + else if (name.equals(Registry.SHA160_HASH)) + prefix = SHA160_PREFIX; + else if (name.equals(Registry.SHA256_HASH)) + prefix = SHA256_PREFIX; + else if (name.equals(Registry.SHA384_HASH)) + prefix = SHA384_PREFIX; + else if (name.equals(Registry.SHA512_HASH)) + prefix = SHA512_PREFIX; + else + throw new UnsupportedOperationException(); // should not happen + } + + /** + * Returns an instance of this object given a designated name of a hash + * function. + * + * @param mdName the canonical name of a hash function. + * @return an instance of this object configured for use with the designated + * options. + * @throws UnsupportedOperationException if the hash function is not + * implemented or does not have an ID listed in RFC-3447. + */ + public static final EMSA_PKCS1_V1_5 getInstance(final String mdName) + { + final IMessageDigest hash = HashFactory.getInstance(mdName); + final String name = hash.name(); + if (! (name.equals(Registry.MD2_HASH) + || name.equals(Registry.MD5_HASH) + || name.equals(Registry.SHA160_HASH) + || name.equals(Registry.SHA256_HASH) + || name.equals(Registry.SHA384_HASH) + || name.equals(Registry.SHA512_HASH))) + throw new UnsupportedOperationException("hash with no OID: " + name); + + return new EMSA_PKCS1_V1_5(hash); + } + + public Object clone() + { + return getInstance(hash.name()); + } + + /** + * Frames the hash of a message, along with an ID of the hash function in + * a DER sequence according to the specifications of EMSA-PKCS1-V1.5 as + * described in RFC-3447 (see class documentation). + * + * @param mHash the byte sequence resulting from applying the message digest + * algorithm Hash to the message M. + * @param emLen intended length in octets of the encoded message, at least + * tLen + 11, where tLen is the octet length of the + * DER encoding T of a certain value computed during the + * encoding operation. + * @return encoded message, an octet string of length emLen. + * @throws IllegalArgumentException if the message is too long, or if the + * intended encoded message length is too short. + */ + public byte[] encode(final byte[] mHash, final int emLen) + { + // 1. Apply the hash function to the message M to produce a hash value + // H: H = Hash(M). + // If the hash function outputs "message too long," output "message + // too long" and stop. + // 2. Encode the algorithm ID for the hash function and the hash value + // into an ASN.1 value of type DigestInfo (see Appendix A.2.4) with + // the Distinguished Encoding Rules (DER), where the type DigestInfo + // has the syntax + // DigestInfo ::= SEQUENCE { + // digestAlgorithm AlgorithmIdentifier, + // digest OCTET STRING + // } + // The first field identifies the hash function and the second contains + // the hash value. Let T be the DER encoding of the DigestInfo value + // (see the notes below) and let tLen be the length in octets of T. + final ByteArrayOutputStream baos = new ByteArrayOutputStream(); + baos.write(prefix, 0, prefix.length); + baos.write(mHash, 0, mHash.length); + final byte[] T = baos.toByteArray(); + final int tLen = T.length; + // 3. If emLen < tLen + 11, output "intended encoded message length too + // short" and stop. + if (emLen < tLen + 11) + throw new IllegalArgumentException("emLen too short"); + // 4. Generate an octet string PS consisting of emLen - tLen - 3 octets + // with hexadecimal value 0xff. The length of PS will be at least 8 + // octets. + final byte[] PS = new byte[emLen - tLen - 3]; + for (int i = 0; i < PS.length; i++) + PS[i] = (byte) 0xFF; + // 5. Concatenate PS, the DER encoding T, and other padding to form the + // encoded message EM as: EM = 0x00 || 0x01 || PS || 0x00 || T. + baos.reset(); + baos.write(0x00); + baos.write(0x01); + baos.write(PS, 0, PS.length); + baos.write(0x00); + baos.write(T, 0, tLen); + final byte[] result = baos.toByteArray(); + baos.reset(); + // 6. Output EM. + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java new file mode 100644 index 000000000..917d96323 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/EMSA_PSS.java @@ -0,0 +1,371 @@ +/* EMSA_PSS.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Configuration; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.util.Util; + +import java.util.Arrays; +import java.util.logging.Logger; + +/** + * An implementation of the EMSA-PSS encoding/decoding scheme. + *

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

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

+ * References: + *

    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ */ +public class EMSA_PSS + implements Cloneable +{ + private static final Logger log = Logger.getLogger(EMSA_PSS.class.getName()); + + /** The underlying hash function to use with this instance. */ + private IMessageDigest hash; + + /** The output size of the hash function in octets. */ + private int hLen; + + /** + * Trivial private constructor to enforce use through Factory method. + * + * @param hash the message digest instance to use with this scheme instance. + */ + private EMSA_PSS(IMessageDigest hash) + { + super(); + + this.hash = hash; + hLen = hash.hashSize(); + } + + /** + * Returns an instance of this object given a designated name of a hash + * function. + * + * @param mdName the canonical name of a hash function. + * @return an instance of this object configured for use with the designated + * options. + */ + public static EMSA_PSS getInstance(String mdName) + { + IMessageDigest hash = HashFactory.getInstance(mdName); + return new EMSA_PSS(hash); + } + + public Object clone() + { + return getInstance(hash.name()); + } + + /** + * The encoding operation EMSA-PSS-Encode computes the hash of a message + * M using a hash function and maps the result to an encoded + * message EM of a specified length using a mask generation + * function. + * + * @param mHash the byte sequence resulting from applying the message digest + * algorithm Hash to the message M. + * @param emBits the maximal bit length of the integer OS2IP(EM), at least + * 8.hLen + 8.sLen + 9. + * @param salt the salt to use when encoding the output. + * @return the encoded message EM, an octet string of length + * emLen = CEILING(emBits / 8). + * @exception IllegalArgumentException if an exception occurs. + */ + public byte[] encode(byte[] mHash, int emBits, byte[] salt) + { + int sLen = salt.length; + // 1. If the length of M is greater than the input limitation for the hash + // function (2**61 - 1 octets for SHA-1) then output "message too long" + // and stop. + // 2. Let mHash = Hash(M), an octet string of length hLen. + if (hLen != mHash.length) + throw new IllegalArgumentException("wrong hash"); + // 3. If emBits < 8.hLen + 8.sLen + 9, output 'encoding error' and stop. + if (emBits < (8 * hLen + 8 * sLen + 9)) + throw new IllegalArgumentException("encoding error"); + int emLen = (emBits + 7) / 8; + // 4. Generate a random octet string salt of length sLen; if sLen = 0, + // then salt is the empty string. + // ...passed as argument to accomodate JCE + // 5. Let M0 = 00 00 00 00 00 00 00 00 || mHash || salt; + // M0 is an octet string of length 8 + hLen + sLen with eight initial zero + // octets. + // 6. Let H = Hash(M0), an octet string of length hLen. + byte[] H; + int i; + synchronized (hash) + { + for (i = 0; i < 8; i++) + hash.update((byte) 0x00); + + hash.update(mHash, 0, hLen); + hash.update(salt, 0, sLen); + H = hash.digest(); + } + // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2 + // zero octets. The length of PS may be 0. + // 8. Let DB = PS || 01 || salt. + byte[] DB = new byte[emLen - sLen - hLen - 2 + 1 + sLen]; + DB[emLen - sLen - hLen - 2] = 0x01; + System.arraycopy(salt, 0, DB, emLen - sLen - hLen - 1, sLen); + // 9. Let dbMask = MGF(H, emLen - hLen - 1). + byte[] dbMask = MGF(H, emLen - hLen - 1); + if (Configuration.DEBUG) + { + log.fine("dbMask (encode): " + Util.toString(dbMask)); + log.fine("DB (encode): " + Util.toString(DB)); + } + // 10. Let maskedDB = DB XOR dbMask. + for (i = 0; i < DB.length; i++) + DB[i] = (byte)(DB[i] ^ dbMask[i]); + // 11. Set the leftmost 8emLen - emBits bits of the leftmost octet in + // maskedDB to zero. + DB[0] &= (0xFF >>> (8 * emLen - emBits)); + // 12. Let EM = maskedDB || H || bc, where bc is the single octet with + // hexadecimal value 0xBC. + byte[] result = new byte[emLen]; + System.arraycopy(DB, 0, result, 0, emLen - hLen - 1); + System.arraycopy(H, 0, result, emLen - hLen - 1, hLen); + result[emLen - 1] = (byte) 0xBC; + // 13. Output EM. + return result; + } + + /** + * The decoding operation EMSA-PSS-Decode recovers the message hash from an + * encoded message EM and compares it to the hash of + * M. + * + * @param mHash the byte sequence resulting from applying the message digest + * algorithm Hash to the message M. + * @param EM the encoded message, an octet string of length + * emLen = CEILING(emBits/8). + * @param emBits the maximal bit length of the integer OS2IP(EM), at least + * 8.hLen + 8.sLen + 9. + * @param sLen the length, in octets, of the expected salt. + * @return true if the result of the verification was + * consistent with the expected reseult; and false if the + * result was inconsistent. + * @exception IllegalArgumentException if an exception occurs. + */ + public boolean decode(byte[] mHash, byte[] EM, int emBits, int sLen) + { + if (Configuration.DEBUG) + { + log.fine("mHash: " + Util.toString(mHash)); + log.fine("EM: " + Util.toString(EM)); + log.fine("emBits: " + String.valueOf(emBits)); + log.fine("sLen: " + String.valueOf(sLen)); + } + if (sLen < 0) + throw new IllegalArgumentException("sLen"); + // 1. If the length of M is greater than the input limitation for the hash + // function (2**61 ? 1 octets for SHA-1) then output 'inconsistent' and + // stop. + // 2. Let mHash = Hash(M), an octet string of length hLen. + if (hLen != mHash.length) + { + if (Configuration.DEBUG) + log.fine("hLen != mHash.length; hLen: " + String.valueOf(hLen)); + throw new IllegalArgumentException("wrong hash"); + } + // 3. If emBits < 8.hLen + 8.sLen + 9, output 'decoding error' and stop. + if (emBits < (8 * hLen + 8 * sLen + 9)) + { + if (Configuration.DEBUG) + log.fine("emBits < (8hLen + 8sLen + 9); sLen: " + + String.valueOf(sLen)); + throw new IllegalArgumentException("decoding error"); + } + int emLen = (emBits + 7) / 8; + // 4. If the rightmost octet of EM does not have hexadecimal value bc, + // output 'inconsistent' and stop. + if ((EM[EM.length - 1] & 0xFF) != 0xBC) + { + if (Configuration.DEBUG) + log.fine("EM does not end with 0xBC"); + return false; + } + // 5. Let maskedDB be the leftmost emLen ? hLen ? 1 octets of EM, and let + // H be the next hLen octets. + // 6. If the leftmost 8.emLen ? emBits bits of the leftmost octet in + // maskedDB are not all equal to zero, output 'inconsistent' and stop. + if ((EM[0] & (0xFF << (8 - (8 * emLen - emBits)))) != 0) + { + if (Configuration.DEBUG) + log.fine("Leftmost 8emLen - emBits bits of EM are not 0s"); + return false; + } + byte[] DB = new byte[emLen - hLen - 1]; + byte[] H = new byte[hLen]; + System.arraycopy(EM, 0, DB, 0, emLen - hLen - 1); + System.arraycopy(EM, emLen - hLen - 1, H, 0, hLen); + // 7. Let dbMask = MGF(H, emLen ? hLen ? 1). + byte[] dbMask = MGF(H, emLen - hLen - 1); + // 8. Let DB = maskedDB XOR dbMask. + int i; + for (i = 0; i < DB.length; i++) + DB[i] = (byte)(DB[i] ^ dbMask[i]); + // 9. Set the leftmost 8.emLen ? emBits bits of DB to zero. + DB[0] &= (0xFF >>> (8 * emLen - emBits)); + if (Configuration.DEBUG) + { + log.fine("dbMask (decode): " + Util.toString(dbMask)); + log.fine("DB (decode): " + Util.toString(DB)); + } + // 10. If the emLen -hLen -sLen -2 leftmost octets of DB are not zero or + // if the octet at position emLen -hLen -sLen -1 is not equal to 0x01, + // output 'inconsistent' and stop. + // IMPORTANT (rsn): this is an error in the specs, the index of the 0x01 + // byte should be emLen -hLen -sLen -2 and not -1! authors have been advised + for (i = 0; i < (emLen - hLen - sLen - 2); i++) + { + if (DB[i] != 0) + { + if (Configuration.DEBUG) + log.fine("DB[" + String.valueOf(i) + "] != 0x00"); + return false; + } + } + if (DB[i] != 0x01) + { // i == emLen -hLen -sLen -2 + if (Configuration.DEBUG) + log.fine("DB's byte at position (emLen -hLen -sLen -2); i.e. " + + String.valueOf(i) + " is not 0x01"); + return false; + } + // 11. Let salt be the last sLen octets of DB. + byte[] salt = new byte[sLen]; + System.arraycopy(DB, DB.length - sLen, salt, 0, sLen); + // 12. Let M0 = 00 00 00 00 00 00 00 00 || mHash || salt; + // M0 is an octet string of length 8 + hLen + sLen with eight initial + // zero octets. + // 13. Let H0 = Hash(M0), an octet string of length hLen. + byte[] H0; + synchronized (hash) + { + for (i = 0; i < 8; i++) + hash.update((byte) 0x00); + + hash.update(mHash, 0, hLen); + hash.update(salt, 0, sLen); + H0 = hash.digest(); + } + // 14. If H = H0, output 'consistent.' Otherwise, output 'inconsistent.' + return Arrays.equals(H, H0); + } + + /** + * A mask generation function takes an octet string of variable length and a + * desired output length as input, and outputs an octet string of the desired + * length. There may be restrictions on the length of the input and output + * octet strings, but such bounds are generally very large. Mask generation + * functions are deterministic; the octet string output is completely + * determined by the input octet string. The output of a mask generation + * function should be pseudorandom, that is, it should be infeasible to + * predict, given one part of the output but not the input, another part of + * the output. The provable security of RSA-PSS relies on the random nature of + * the output of the mask generation function, which in turn relies on the + * random nature of the underlying hash function. + * + * @param Z a seed. + * @param l the desired output length in octets. + * @return the mask. + * @exception IllegalArgumentException if the desired output length is too + * long. + */ + private byte[] MGF(byte[] Z, int l) + { + // 1. If l > (2**32).hLen, output 'mask too long' and stop. + if (l < 1 || (l & 0xFFFFFFFFL) > ((hLen & 0xFFFFFFFFL) << 32L)) + throw new IllegalArgumentException("mask too long"); + // 2. Let T be the empty octet string. + byte[] result = new byte[l]; + // 3. For i = 0 to CEILING(l/hLen) ? 1, do + int limit = ((l + hLen - 1) / hLen) - 1; + IMessageDigest hashZ = null; + hashZ = (IMessageDigest) hash.clone(); + hashZ.digest(); + hashZ.update(Z, 0, Z.length); + IMessageDigest hashZC = null; + byte[] t; + int sofar = 0; + int length; + for (int i = 0; i < limit; i++) + { + // 3.1 Convert i to an octet string C of length 4 with the primitive + // I2OSP: C = I2OSP(i, 4). + // 3.2 Concatenate the hash of the seed Z and C to the octet string T: + // T = T || Hash(Z || C) + hashZC = (IMessageDigest) hashZ.clone(); + hashZC.update((byte)(i >>> 24)); + hashZC.update((byte)(i >>> 16)); + hashZC.update((byte)(i >>> 8)); + hashZC.update((byte) i); + t = hashZC.digest(); + length = l - sofar; + length = (length > hLen ? hLen : length); + System.arraycopy(t, 0, result, sofar, length); + sofar += length; + } + // 4. Output the leading l octets of T as the octet string mask. + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSA.java b/libjava/classpath/gnu/java/security/sig/rsa/RSA.java new file mode 100644 index 000000000..343b2cf65 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSA.java @@ -0,0 +1,324 @@ +/* RSA.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Properties; +import gnu.java.security.util.PRNG; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateCrtKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; + +/** + * Utility methods related to the RSA algorithm. + *

+ * References: + *

    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
  3. Public-Key Cryptography + * Standards (PKCS) #1:
    + * RSA Cryptography Specifications Version 2.1.
    + * Jakob Jonsson and Burt Kaliski.
  4. + *
  5. + * Remote timing attacks are practical
    + * D. Boneh and D. Brumley.
  6. + *
+ */ +public class RSA +{ + private static final BigInteger ZERO = BigInteger.ZERO; + + private static final BigInteger ONE = BigInteger.ONE; + + /** Our default source of randomness. */ + private static final PRNG prng = PRNG.getInstance(); + + /** Trivial private constructor to enforce Singleton pattern. */ + private RSA() + { + super(); + } + + /** + * An implementation of the RSASP method: Assuming that the designated + * RSA private key is a valid one, this method computes a signature + * representative for a designated message representative signed + * by the holder of the designated RSA private key. + * + * @param K the RSA private key. + * @param m the message representative: an integer between + * 0 and n - 1, where n + * is the RSA modulus. + * @return the signature representative, an integer between + * 0 and n - 1, where n + * is the RSA modulus. + * @throws ClassCastException if K is not an RSA one. + * @throws IllegalArgumentException if m (the message + * representative) is out of range. + */ + public static final BigInteger sign(final PrivateKey K, final BigInteger m) + { + try + { + return RSADP((RSAPrivateKey) K, m); + } + catch (IllegalArgumentException x) + { + throw new IllegalArgumentException("message representative out of range"); + } + } + + /** + * An implementation of the RSAVP method: Assuming that the designated + * RSA public key is a valid one, this method computes a message + * representative for the designated signature representative + * generated by an RSA private key, for a message intended for the holder of + * the designated RSA public key. + * + * @param K the RSA public key. + * @param s the signature representative, an integer between + * 0 and n - 1, where n + * is the RSA modulus. + * @return a message representative: an integer between 0 + * and n - 1, where n is the RSA + * modulus. + * @throws ClassCastException if K is not an RSA one. + * @throws IllegalArgumentException if s (the signature + * representative) is out of range. + */ + public static final BigInteger verify(final PublicKey K, final BigInteger s) + { + try + { + return RSAEP((RSAPublicKey) K, s); + } + catch (IllegalArgumentException x) + { + throw new IllegalArgumentException("signature representative out of range"); + } + } + + /** + * An implementation of the RSAEP algorithm. + * + * @param K the recipient's RSA public key. + * @param m the message representative as an MPI. + * @return the resulting MPI --an MPI between 0 and + * n - 1 (n being the public shared + * modulus)-- that will eventually be padded with an appropriate + * framing/padding scheme. + * @throws ClassCastException if K is not an RSA one. + * @throws IllegalArgumentException if m, the message + * representative is not between 0 and + * n - 1 (n being the public shared + * modulus). + */ + public static final BigInteger encrypt(final PublicKey K, final BigInteger m) + { + try + { + return RSAEP((RSAPublicKey) K, m); + } + catch (IllegalArgumentException x) + { + throw new IllegalArgumentException("message representative out of range"); + } + } + + /** + * An implementation of the RSADP algorithm. + * + * @param K the recipient's RSA private key. + * @param c the ciphertext representative as an MPI. + * @return the message representative, an MPI between 0 and + * n - 1 (n being the shared public + * modulus). + * @throws ClassCastException if K is not an RSA one. + * @throws IllegalArgumentException if c, the ciphertext + * representative is not between 0 and + * n - 1 (n being the shared public + * modulus). + */ + public static final BigInteger decrypt(final PrivateKey K, final BigInteger c) + { + try + { + return RSADP((RSAPrivateKey) K, c); + } + catch (IllegalArgumentException x) + { + throw new IllegalArgumentException("ciphertext representative out of range"); + } + } + + /** + * Converts a multi-precision integer (MPI) s into an + * octet sequence of length k. + * + * @param s the multi-precision integer to convert. + * @param k the length of the output. + * @return the result of the transform. + * @exception IllegalArgumentException if the length in octets of meaningful + * bytes of s is greater than k. + */ + public static final byte[] I2OSP(final BigInteger s, final int k) + { + byte[] result = s.toByteArray(); + if (result.length < k) + { + final byte[] newResult = new byte[k]; + System.arraycopy(result, 0, newResult, k - result.length, result.length); + result = newResult; + } + else if (result.length > k) + { // leftmost extra bytes should all be 0 + final int limit = result.length - k; + for (int i = 0; i < limit; i++) + { + if (result[i] != 0x00) + throw new IllegalArgumentException("integer too large"); + } + final byte[] newResult = new byte[k]; + System.arraycopy(result, limit, newResult, 0, k); + result = newResult; + } + return result; + } + + private static final BigInteger RSAEP(final RSAPublicKey K, final BigInteger m) + { + // 1. If the representative m is not between 0 and n - 1, output + // "representative out of range" and stop. + final BigInteger n = K.getModulus(); + if (m.compareTo(ZERO) < 0 || m.compareTo(n.subtract(ONE)) > 0) + throw new IllegalArgumentException(); + // 2. Let c = m^e mod n. + final BigInteger e = K.getPublicExponent(); + final BigInteger result = m.modPow(e, n); + // 3. Output c. + return result; + } + + private static final BigInteger RSADP(final RSAPrivateKey K, BigInteger c) + { + // 1. If the representative c is not between 0 and n - 1, output + // "representative out of range" and stop. + final BigInteger n = K.getModulus(); + if (c.compareTo(ZERO) < 0 || c.compareTo(n.subtract(ONE)) > 0) + throw new IllegalArgumentException(); + // 2. The representative m is computed as follows. + BigInteger result; + if (! (K instanceof RSAPrivateCrtKey)) + { + // a. If the first form (n, d) of K is used, let m = c^d mod n. + final BigInteger d = K.getPrivateExponent(); + result = c.modPow(d, n); + } + else + { + // from [3] p.13 --see class docs: + // The RSA blinding operation calculates x = (r^e) * g mod n before + // decryption, where r is random, e is the RSA encryption exponent, and + // g is the ciphertext to be decrypted. x is then decrypted as normal, + // followed by division by r, i.e. (x^e) / r mod n. Since r is random, + // x is random and timing the decryption should not reveal information + // about the key. Note that r should be a new random number for every + // decryption. + final boolean rsaBlinding = Properties.doRSABlinding(); + BigInteger r = null; + BigInteger e = null; + if (rsaBlinding) + { // pre-decryption + r = newR(n); + e = ((RSAPrivateCrtKey) K).getPublicExponent(); + final BigInteger x = r.modPow(e, n).multiply(c).mod(n); + c = x; + } + // b. If the second form (p, q, dP, dQ, qInv) and (r_i, d_i, t_i) + // of K is used, proceed as follows: + final BigInteger p = ((RSAPrivateCrtKey) K).getPrimeP(); + final BigInteger q = ((RSAPrivateCrtKey) K).getPrimeQ(); + final BigInteger dP = ((RSAPrivateCrtKey) K).getPrimeExponentP(); + final BigInteger dQ = ((RSAPrivateCrtKey) K).getPrimeExponentQ(); + final BigInteger qInv = ((RSAPrivateCrtKey) K).getCrtCoefficient(); + // i. Let m_1 = c^dP mod p and m_2 = c^dQ mod q. + final BigInteger m_1 = c.modPow(dP, p); + final BigInteger m_2 = c.modPow(dQ, q); + // ii. If u > 2, let m_i = c^(d_i) mod r_i, i = 3, ..., u. + // iii. Let h = (m_1 - m_2) * qInv mod p. + final BigInteger h = m_1.subtract(m_2).multiply(qInv).mod(p); + // iv. Let m = m_2 + q * h. + result = m_2.add(q.multiply(h)); + if (rsaBlinding) // post-decryption + result = result.multiply(r.modInverse(n)).mod(n); + } + // 3. Output m + return result; + } + + /** + * Returns a random MPI with a random bit-length of the form 8b, + * where b is in the range [32..64]. + * + * @return a random MPI whose length in bytes is between 32 and 64 inclusive. + */ + private static final BigInteger newR(final BigInteger N) + { + final int upper = (N.bitLength() + 7) / 8; + final int lower = upper / 2; + final byte[] bl = new byte[1]; + int b; + do + { + prng.nextBytes(bl); + b = bl[0] & 0xFF; + } + while (b < lower || b > upper); + final byte[] buffer = new byte[b]; // 256-bit MPI + prng.nextBytes(buffer); + return new BigInteger(1, buffer); + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java new file mode 100644 index 000000000..1420331de --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPKCS1V1_5Signature.java @@ -0,0 +1,224 @@ +/* RSAPKCS1V1_5Signature.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.sig.BaseSignature; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.Arrays; + +/** + * The RSA-PKCS1-V1.5 signature scheme is a digital signature scheme with + * appendix (SSA) combining the RSA algorithm with the EMSA-PKCS1-v1_5 encoding + * method. + *

+ * References: + *

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

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

+ *

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

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

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

+ * The output of the encoder, and the input of the decoder, of this codec are + * then the raw bytes of such a BIT STRING; i.e. not the DER-encoded + * form itself. + *

+ * Our implementation of the RSA PKCS1 signature algorithm outputs a byte array + * as the result of generating a digital signature, in accordance with RFC-2313. + * As a consequence, the encoder and decoder of this codec, simply pass through + * such a byte array. + *

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

+ *

+ * ...
+ * import gnu.java.security.der.BitString;
+ * import gnu.java.security.der.DER;
+ * import gnu.java.security.der.DERValue;
+ * ...
+ * DERValue bitString = new DERValue(DER.BIT_STRING, new BitString(sigBytes));
+ * ...
+ * 
+ */ +public class RSAPKCS1V1_5SignatureX509Codec + implements ISignatureCodec +{ + // default 0-arguments constructor + + public int getFormatID() + { + return Registry.X509_ENCODING_ID; + } + + /** + * Encodes an RSA Signature output as a signature BIT STRING as + * defined in the documentation of this class. + * + * @param signature the output of the RSA PKCS1 (v1.5) signature algorithm; + * i.e. the value returned by the invocation of + * {@link gnu.java.security.sig.ISignature#sign()} method. In the + * case of the RSA PKCS1 (v1.5) signature this is an array of bytes. + * @return the raw bytes of an RSA signature which could be then used as the + * contents of a BIT STRING as per rfc-2459. + */ + public byte[] encodeSignature(Object signature) + { + byte[] result = (byte[]) signature; + return result; + } + + /** + * Decodes a signature as defined in the documentation of this class. + * + * @param input the byte array to unmarshall into a valid RSA PKCS1 (v1.5) + * signature instance; i.e. a byte array. MUST NOT be null. + * @return an array of raw bytes decoded from the designated input. In the + * case of RSA PKCS1 (v1.5) this is the same as the input. + * @throw InvalidParameterException if the input array is null. + */ + public Object decodeSignature(byte[] input) + { + if (input == null) + throw new InvalidParameterException("Input bytes MUST NOT be null"); + + return input; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java new file mode 100644 index 000000000..d8f8327f1 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignature.java @@ -0,0 +1,255 @@ +/* RSAPSSSignature.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Configuration; +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.sig.BaseSignature; +import gnu.java.security.util.Util; + +import java.math.BigInteger; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.interfaces.RSAPrivateKey; +import java.security.interfaces.RSAPublicKey; +import java.util.logging.Logger; + +/** + * The RSA-PSS signature scheme is a public-key encryption scheme combining the + * RSA algorithm with the Probabilistic Signature Scheme (PSS) encoding method. + *

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

+ * References: + *

    + *
  1. + * RSA-PSS Signature Scheme with Appendix, part B.
    + * Primitive specification and supporting documentation.
    + * Jakob Jonsson and Burt Kaliski.
  2. + *
+ */ +public class RSAPSSSignature + extends BaseSignature +{ + private static final Logger log = Logger.getLogger(RSAPSSSignature.class.getName()); + + /** The underlying EMSA-PSS instance for this object. */ + private EMSA_PSS pss; + + /** The desired length in octets of the EMSA-PSS salt. */ + private int sLen; + + /** + * Default 0-arguments constructor. Uses SHA-1 as the default hash and a + * 0-octet salt. + */ + public RSAPSSSignature() + { + this(Registry.SHA160_HASH, 0); + } + + /** + * Constructs an instance of this object using the designated message digest + * algorithm as its underlying hash function, and having 0-octet salt. + * + * @param mdName the canonical name of the underlying hash function. + */ + public RSAPSSSignature(String mdName) + { + this(mdName, 0); + } + + /** + * Constructs an instance of this object using the designated message digest + * algorithm as its underlying hash function. + * + * @param mdName the canonical name of the underlying hash function. + * @param sLen the desired length in octets of the salt to use for encoding / + * decoding signatures. + */ + public RSAPSSSignature(String mdName, int sLen) + { + this(HashFactory.getInstance(mdName), sLen); + } + + public RSAPSSSignature(IMessageDigest md, int sLen) + { + super(Registry.RSA_PSS_SIG, md); + + pss = EMSA_PSS.getInstance(md.name()); + this.sLen = sLen; + } + + /** Private constructor for cloning purposes. */ + private RSAPSSSignature(RSAPSSSignature that) + { + this(that.md.name(), that.sLen); + + this.publicKey = that.publicKey; + this.privateKey = that.privateKey; + this.md = (IMessageDigest) that.md.clone(); + this.pss = (EMSA_PSS) that.pss.clone(); + } + + public Object clone() + { + return new RSAPSSSignature(this); + } + + protected void setupForVerification(PublicKey k) + throws IllegalArgumentException + { + if (! (k instanceof RSAPublicKey)) + throw new IllegalArgumentException(); + + publicKey = (RSAPublicKey) k; + } + + protected void setupForSigning(PrivateKey k) throws IllegalArgumentException + { + if (! (k instanceof RSAPrivateKey)) + throw new IllegalArgumentException(); + + privateKey = (RSAPrivateKey) k; + } + + protected Object generateSignature() throws IllegalStateException + { + // 1. Apply the EMSA-PSS encoding operation to the message M to produce an + // encoded message EM of length CEILING((modBits ? 1)/8) octets such + // that the bit length of the integer OS2IP(EM) is at most modBits ? 1: + // EM = EMSA-PSS-Encode(M,modBits ? 1). + // Note that the octet length of EM will be one less than k if + // modBits ? 1 is divisible by 8. If the encoding operation outputs + // 'message too long' or 'encoding error,' then output 'message too + // long' or 'encoding error' and stop. + int modBits = ((RSAPrivateKey) privateKey).getModulus().bitLength(); + byte[] salt = new byte[sLen]; + this.nextRandomBytes(salt); + byte[] EM = pss.encode(md.digest(), modBits - 1, salt); + if (Configuration.DEBUG) + log.fine("EM (sign): " + Util.toString(EM)); + // 2. Convert the encoded message EM to an integer message representative + // m (see Section 1.2.2): m = OS2IP(EM). + BigInteger m = new BigInteger(1, EM); + // 3. Apply the RSASP signature primitive to the public key K and the + // message representative m to produce an integer signature + // representative s: s = RSASP(K,m). + BigInteger s = RSA.sign(privateKey, m); + // 4. Convert the signature representative s to a signature S of length k + // octets (see Section 1.2.1): S = I2OSP(s, k). + // 5. Output the signature S. + int k = (modBits + 7) / 8; + // return encodeSignature(s, k); + return RSA.I2OSP(s, k); + } + + protected boolean verifySignature(Object sig) throws IllegalStateException + { + if (publicKey == null) + throw new IllegalStateException(); + // byte[] S = decodeSignature(sig); + byte[] S = (byte[]) sig; + // 1. If the length of the signature S is not k octets, output 'signature + // invalid' and stop. + int modBits = ((RSAPublicKey) publicKey).getModulus().bitLength(); + int k = (modBits + 7) / 8; + if (S.length != k) + return false; + // 2. Convert the signature S to an integer signature representative s: + // s = OS2IP(S). + BigInteger s = new BigInteger(1, S); + // 3. Apply the RSAVP verification primitive to the public key (n, e) and + // the signature representative s to produce an integer message + // representative m: m = RSAVP((n, e), s). + // If RSAVP outputs 'signature representative out of range,' then + // output 'signature invalid' and stop. + BigInteger m = null; + try + { + m = RSA.verify(publicKey, s); + } + catch (IllegalArgumentException x) + { + return false; + } + // 4. Convert the message representative m to an encoded message EM of + // length emLen = CEILING((modBits - 1)/8) octets, where modBits is + // equal to the bit length of the modulus: EM = I2OSP(m, emLen). + // Note that emLen will be one less than k if modBits - 1 is divisible + // by 8. If I2OSP outputs 'integer too large,' then output 'signature + // invalid' and stop. + int emBits = modBits - 1; + int emLen = (emBits + 7) / 8; + byte[] EM = m.toByteArray(); + if (Configuration.DEBUG) + log.fine("EM (verify): " + Util.toString(EM)); + if (EM.length > emLen) + return false; + else if (EM.length < emLen) + { + byte[] newEM = new byte[emLen]; + System.arraycopy(EM, 0, newEM, emLen - EM.length, EM.length); + EM = newEM; + } + // 5. Apply the EMSA-PSS decoding operation to the message M and the + // encoded message EM: Result = EMSA-PSS-Decode(M, EM, emBits). If + // Result = 'consistent,' output 'signature verified.' Otherwise, + // output 'signature invalid.' + byte[] mHash = md.digest(); + boolean result = false; + try + { + result = pss.decode(mHash, EM, emBits, sLen); + } + catch (IllegalArgumentException x) + { + result = false; + } + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java new file mode 100644 index 000000000..b147ea3ea --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSAPSSSignatureRawCodec.java @@ -0,0 +1,134 @@ +/* RSAPSSSignatureRawCodec.java -- + Copyright (C) 2001, 2002, 2003, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import gnu.java.security.Registry; +import gnu.java.security.sig.ISignatureCodec; + +import java.io.ByteArrayOutputStream; + +/** + * An object that implements the {@link ISignatureCodec} operations for the + * Raw format to use with RSA-PSS signatures. + */ +public class RSAPSSSignatureRawCodec + implements ISignatureCodec +{ + // implicit 0-arguments constructor + + public int getFormatID() + { + return RAW_FORMAT; + } + + /** + * Returns the encoded form of the designated RSA-PSS signature object + * according to the Raw format supported by this library. + *

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

    + *
  1. 4-byte magic consisting of the value of the literal + * {@link Registry#MAGIC_RAW_RSA_PSS_SIGNATURE}, + *
  2. + *
  3. 1-byte version consisting of the constant: 0x01,
  4. + *
  5. 4-byte count of following bytes representing the RSA-PSS signature + * bytes in internet order,
  6. + *
  7. the RSA-PSS signature bytes in internet order.
  8. + *
+ * + * @param signature the signature to encode, consisting of the output of the + * sign() method of a {@link RSAPSSSignature} instance + * --a byte array. + * @return the Raw format encoding of the designated signature. + * @exception IllegalArgumentException if the designated signature is not an + * RSA-PSS one. + */ + public byte[] encodeSignature(Object signature) + { + byte[] buffer; + try + { + buffer = (byte[]) signature; + } + catch (Exception x) + { + throw new IllegalArgumentException("signature"); + } + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + // magic + baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[0]); + baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[1]); + baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[2]); + baos.write(Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[3]); + // version + baos.write(0x01); + // signature bytes + int length = buffer.length; + baos.write( length >>> 24); + baos.write((length >>> 16) & 0xFF); + baos.write((length >>> 8) & 0xFF); + baos.write(length & 0xFF); + baos.write(buffer, 0, length); + return baos.toByteArray(); + } + + public Object decodeSignature(byte[] k) + { + // magic + if (k[0] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[0] + || k[1] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[1] + || k[2] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[2] + || k[3] != Registry.MAGIC_RAW_RSA_PSS_SIGNATURE[3]) + throw new IllegalArgumentException("magic"); + // version + if (k[4] != 0x01) + throw new IllegalArgumentException("version"); + int i = 5; + int l; + // signature bytes + l = k[i++] << 24 + | (k[i++] & 0xFF) << 16 + | (k[i++] & 0xFF) << 8 + | (k[i++] & 0xFF); + byte[] result = new byte[l]; + System.arraycopy(k, i, result, 0, l); + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java b/libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java new file mode 100644 index 000000000..ba5121b46 --- /dev/null +++ b/libjava/classpath/gnu/java/security/sig/rsa/RSASignatureFactory.java @@ -0,0 +1,176 @@ +/* RSASignatureFactory.java -- A Factory class to instantiate RSA Signatures + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.sig.rsa; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import gnu.java.security.Registry; +import gnu.java.security.hash.HashFactory; +import gnu.java.security.hash.IMessageDigest; +import gnu.java.security.sig.ISignature; + +/** + * A Factory class to instantiate RSA Signature classes. + */ +public class RSASignatureFactory +{ + private static Set names; + + /** + * Private constructor to enforce usage through Factory (class) methods. + */ + private RSASignatureFactory() + { + super(); + } + + /** + * Returns a new instance of an RSA Signature given its name. The name of an + * RSA Signature always starts with rsa-, followed by either + * pss or pkcs1_v1.5. An optional message digest + * name, to be used with the RSA signature may be specified by appending the + * hyphen chanaracter - followed by the canonical message digest + * algorithm name. When no message digest algorithm name is given, SHA-160 is + * used. + * + * @param name the composite RSA signature name. + * @return a new instance of an RSA Signature algorithm implementation. + * Returns null if the given name does not correspond to any + * supported RSA Signature encoding and message digest combination. + */ + public static final ISignature getInstance(String name) + { + if (name == null) + return null; + + name = name.trim(); + if (name.length() == 0) + return null; + + name = name.toLowerCase(); + if (! name.startsWith(Registry.RSA_SIG_PREFIX)) + return null; + + name = name.substring(Registry.RSA_SIG_PREFIX.length()).trim(); + if (name.startsWith(Registry.RSA_PSS_ENCODING)) + return getPSSSignature(name); + else if (name.startsWith(Registry.RSA_PKCS1_V1_5_ENCODING)) + return getPKCS1Signature(name); + else + return null; + } + + /** + * Returns a {@link Set} of names of RSA signatures supported by this + * Factory. + * + * @return a {@link Set} of RSA Signature algorithm names (Strings). + */ + public static synchronized final Set getNames() + { + if (names == null) + { + Set hashNames = HashFactory.getNames(); + HashSet hs = new HashSet(); + for (Iterator it = hashNames.iterator(); it.hasNext();) + { + String mdName = (String) it.next(); + hs.add(Registry.RSA_PSS_SIG + "-" + mdName); + } + + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.MD2_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.MD5_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA160_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA256_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA384_HASH); + hs.add(Registry.RSA_PKCS1_V1_5_SIG + "-" + Registry.SHA512_HASH); + + names = Collections.unmodifiableSet(hs); + } + + return names; + } + + private static final ISignature getPSSSignature(String name) + { + name = name.substring(Registry.RSA_PSS_ENCODING.length()).trim(); + // remove the hyphen if found at the beginning + if (name.startsWith("-")) + name = name.substring(1).trim(); + + IMessageDigest md; + if (name.length() == 0) + md = HashFactory.getInstance(Registry.SHA160_HASH); + else + { + // check if there is such a hash + md = HashFactory.getInstance(name); + if (md == null) + return null; + } + + ISignature result = new RSAPSSSignature(md, 0); + return result; + } + + private static final ISignature getPKCS1Signature(String name) + { + name = name.substring(Registry.RSA_PKCS1_V1_5_ENCODING.length()).trim(); + // remove the hyphen if found at the beginning + if (name.startsWith("-")) + name = name.substring(1).trim(); + + IMessageDigest md; + if (name.length() == 0) + md = HashFactory.getInstance(Registry.SHA160_HASH); + else + { + // check if there is such a hash + md = HashFactory.getInstance(name); + if (md == null) + return null; + } + + ISignature result = new RSAPKCS1V1_5Signature(md); + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/util/ByteArray.java b/libjava/classpath/gnu/java/security/util/ByteArray.java new file mode 100644 index 000000000..a9b9e5d00 --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/ByteArray.java @@ -0,0 +1,111 @@ +/* ByteArray.java -- wrapper around a byte array, with nice toString output. + Copyright (C) 2005 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import gnu.java.lang.CPStringBuilder; + +import java.io.PrintWriter; +import java.io.StringWriter; + +public final class ByteArray +{ + private final byte[] value; + + public ByteArray (final byte[] value) + { + this.value = value; + } + + public byte[] getValue () + { + return value; + } + + public String toString () + { + StringWriter str = new StringWriter (); + PrintWriter out = new PrintWriter (str); + int i = 0; + int len = value.length; + while (i < len) + { + out.print (formatInt (i, 16, 8)); + out.print (" "); + int l = Math.min (16, len - i); + String s = toHexString (value, i, l, ' '); + out.print (s); + for (int j = 56 - (56 - s.length ()); j < 56; j++) + out.print (" "); + for (int j = 0; j < l; j++) + { + byte b = value[i+j]; + if ((b & 0xFF) < 0x20 || (b & 0xFF) > 0x7E) + out.print ("."); + else + out.print ((char) (b & 0xFF)); + } + out.println (); + i += 16; + } + return str.toString (); + } + + public static String toHexString (byte[] buf, int off, int len, char sep) + { + CPStringBuilder str = new CPStringBuilder(); + for (int i = 0; i < len; i++) + { + str.append (Character.forDigit (buf[i+off] >>> 4 & 0x0F, 16)); + str.append (Character.forDigit (buf[i+off] & 0x0F, 16)); + if (i < len - 1) + str.append(sep); + } + return str.toString(); + } + + public static String formatInt (int value, int radix, int len) + { + String s = Integer.toString (value, radix); + CPStringBuilder buf = new CPStringBuilder (); + for (int j = 0; j < len - s.length(); j++) + buf.append ("0"); + buf.append (s); + return buf.toString(); + } +} diff --git a/libjava/classpath/gnu/java/security/util/ByteBufferOutputStream.java b/libjava/classpath/gnu/java/security/util/ByteBufferOutputStream.java new file mode 100644 index 000000000..642ccdf68 --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/ByteBufferOutputStream.java @@ -0,0 +1,118 @@ +/* ByteBufferOutputStream.java -- output stream with a growable underlying + byte buffer. + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import java.io.IOException; +import java.io.OutputStream; + +import java.nio.ByteBuffer; + +/** + * An output stream that writes bytes to a ByteBuffer, which will be resized + * if more space is needed. + * + * @author Casey Marshall (csm@gnu.org) + */ +public class ByteBufferOutputStream extends OutputStream +{ + private ByteBuffer buffer; + + public ByteBufferOutputStream() + { + this(256); + } + + public ByteBufferOutputStream(int initialCapacity) + { + buffer = ByteBuffer.allocate(initialCapacity); + } + + /* (non-Javadoc) + * @see java.io.OutputStream#write(int) + */ + public @Override synchronized void write(int b) throws IOException + { + if (!buffer.hasRemaining()) + growBuffer(); + buffer.put((byte) b); + } + + public @Override synchronized void write(byte[] b, int offset, int length) + { + if (buffer.remaining() < length) + growBuffer(); + buffer.put(b, offset, length); + } + + public @Override void write(byte[] b) + { + write(b, 0, b.length); + } + + /** + * Get the current state of the buffer. The returned buffer will have + * its position set to zero, its capacity set to the current limit, + * and its limit set to its capacity. + * + * @return The buffer. + */ + public ByteBuffer buffer() + { + return ((ByteBuffer) buffer.duplicate().flip()).slice(); + } + + public String toString() + { + return super.toString() + " [ buffer: " + buffer + " ]"; + } + + private void growBuffer() + { + int newCapacity = buffer.capacity(); + if (newCapacity < 16384) // If the buffer isn't huge yet, double its size + newCapacity = newCapacity << 1; + else // Otherwize, increment by a bit. + newCapacity += 4096; + ByteBuffer newBuffer = ByteBuffer.allocate(newCapacity); + buffer.flip(); + newBuffer.put(buffer); + buffer = newBuffer; + } +} diff --git a/libjava/classpath/gnu/java/security/util/DerUtil.java b/libjava/classpath/gnu/java/security/util/DerUtil.java new file mode 100644 index 000000000..26232ba98 --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/DerUtil.java @@ -0,0 +1,64 @@ +/* DerUtil.java -- Utility methods for DER read/write operations + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import gnu.java.security.der.DEREncodingException; +import gnu.java.security.der.DERValue; + +import java.math.BigInteger; + +/** + * Utility methods for DER encoding handling. + */ +public abstract class DerUtil +{ + public static final void checkIsConstructed(DERValue v, String msg) + throws DEREncodingException + { + if (! v.isConstructed()) + throw new DEREncodingException(msg); + } + + public static final void checkIsBigInteger(DERValue v, String msg) + throws DEREncodingException + { + if (! (v.getValue() instanceof BigInteger)) + throw new DEREncodingException(msg); + } +} diff --git a/libjava/classpath/gnu/java/security/util/ExpirableObject.java b/libjava/classpath/gnu/java/security/util/ExpirableObject.java new file mode 100644 index 000000000..e24af249a --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/ExpirableObject.java @@ -0,0 +1,150 @@ +/* ExpirableObject.java -- an object that is automatically destroyed. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import java.util.Timer; +import java.util.TimerTask; + +import javax.security.auth.DestroyFailedException; +import javax.security.auth.Destroyable; + +/** + * The base class for objects with sensitive data that are automatically + * destroyed after a timeout elapses. On creation, an object that extends this + * class will automatically be added to a {@link Timer} object that, once a + * timeout elapses, will automatically call the {@link Destroyable#destroy()} + * method. + *

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

+ * Note that if a {@link DestroyFailedException} occurs when the timeout + * expires, it will not be reported. + * + * @see Destroyable + */ +public abstract class ExpirableObject + implements Destroyable +{ + /** + * The default timeout, used in the default constructor. + */ + public static final long DEFAULT_TIMEOUT = 3600000L; + + /** + * The timer that expires instances. + */ + private static final Timer EXPIRER = new Timer(true); + + /** + * A reference to the task that will destroy this object when the timeout + * expires. + */ + private final Destroyer destroyer; + + /** + * Create a new expirable object that will expire after one hour. + */ + protected ExpirableObject() + { + this(DEFAULT_TIMEOUT); + } + + /** + * Create a new expirable object that will expire after the specified timeout. + * + * @param delay The delay before expiration. + * @throws IllegalArgumentException If delay is negative, or if + * delay + System.currentTimeMillis() is negative. + */ + protected ExpirableObject(final long delay) + { + destroyer = new Destroyer(this); + EXPIRER.schedule(destroyer, delay); + } + + /** + * Destroys this object. This method calls {@link #doDestroy}, then, if no + * exception is thrown, cancels the task that would destroy this object when + * the timeout is reached. + * + * @throws DestroyFailedException If this operation fails. + */ + public final void destroy() throws DestroyFailedException + { + doDestroy(); + destroyer.cancel(); + } + + /** + * Subclasses must implement this method instead of the {@link + * Destroyable#destroy()} method. + * + * @throws DestroyFailedException If this operation fails. + */ + protected abstract void doDestroy() throws DestroyFailedException; + + /** + * The task that destroys the target when the timeout elapses. + */ + private final class Destroyer + extends TimerTask + { + private final ExpirableObject target; + + Destroyer(final ExpirableObject target) + { + super(); + this.target = target; + } + + public void run() + { + try + { + if (! target.isDestroyed()) + target.doDestroy(); + } + catch (DestroyFailedException dfe) + { + } + } + } +} diff --git a/libjava/classpath/gnu/java/security/util/FormatUtil.java b/libjava/classpath/gnu/java/security/util/FormatUtil.java new file mode 100644 index 000000000..35da322b8 --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/FormatUtil.java @@ -0,0 +1,140 @@ +/* FormatUtil.java -- Encoding and decoding format utility methods + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import gnu.java.security.Registry; + +/** + * Encoding and decoding format utility methods. + */ +public class FormatUtil +{ + /** Trivial constructor to enforce Singleton pattern. */ + private FormatUtil() + { + super(); + } + + /** + * Returns the fully qualified name of the designated encoding ID. + * + * @param formatID the unique identifier of the encoding format. + * @return the fully qualified name of the designated format. Returns + * null if no such encoding format is known. + */ + public static final String getEncodingName(int formatID) + { + String result = null; + switch (formatID) + { + case Registry.RAW_ENCODING_ID: + result = Registry.RAW_ENCODING; + break; + case Registry.X509_ENCODING_ID: + result = Registry.X509_ENCODING; + break; + case Registry.PKCS8_ENCODING_ID: + result = Registry.PKCS8_ENCODING; + break; + case Registry.ASN1_ENCODING_ID: + result = Registry.ASN1_ENCODING; + break; + } + + return result; + } + + /** + * Returns the short name of the designated encoding ID. This is used by the + * JCE Adapters. + * + * @param formatID the unique identifier of the encoding format. + * @return the short name of the designated format. Returns null + * if no such encoding format is known. + */ + public static final String getEncodingShortName(int formatID) + { + String result = null; + switch (formatID) + { + case Registry.RAW_ENCODING_ID: + result = Registry.RAW_ENCODING_SHORT_NAME; + break; + case Registry.X509_ENCODING_ID: + result = Registry.X509_ENCODING_SORT_NAME; + break; + case Registry.PKCS8_ENCODING_ID: + result = Registry.PKCS8_ENCODING_SHORT_NAME; + break; + case Registry.ASN1_ENCODING_ID: + result = Registry.ASN1_ENCODING_SHORT_NAME; + break; + } + + return result; + } + + /** + * Returns the identifier of the encoding format given its short name. + * + * @param name the case-insensitive canonical short name of an encoding + * format. + * @return the identifier of the designated encoding format, or 0 + * if the name does not correspond to any known format. + */ + public static final int getFormatID(String name) + { + if (name == null) + return 0; + + name = name.trim(); + if (name.length() == 0) + return 0; + + int result = 0; + if (name.equalsIgnoreCase(Registry.RAW_ENCODING_SHORT_NAME)) + result = Registry.RAW_ENCODING_ID; + else if (name.equalsIgnoreCase(Registry.X509_ENCODING_SORT_NAME)) + result = Registry.X509_ENCODING_ID; + else if (name.equalsIgnoreCase(Registry.PKCS8_ENCODING_SHORT_NAME)) + result = Registry.PKCS8_ENCODING_ID; + + return result; + } +} diff --git a/libjava/classpath/gnu/java/security/util/IntegerUtil.java b/libjava/classpath/gnu/java/security/util/IntegerUtil.java new file mode 100644 index 000000000..106dc4d66 --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/IntegerUtil.java @@ -0,0 +1,109 @@ +/* IntegerUtil.java -- JDK 5 Integer methods with 1.4 API + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * Utility class which offers Integer related methods found in RI's version 5 + * but written with RI's 1.4 API. + */ +public abstract class IntegerUtil +{ + /** Maximum size of our cache of constructed Integers. */ + private static final int CACHE_SIZE = 100; + /** LRU (Least Recently Used) cache, of the last accessed 100 Integers. */ + private static final Map cache = new LinkedHashMap(CACHE_SIZE + 1, 0.75F, true) + { + public boolean removeEldestEntry(Map.Entry entry) + { + return size() > CACHE_SIZE; + } + }; + + /** Trivial private constructor to enforce Singleton usage. */ + private IntegerUtil() + { + super(); + } + + /** + * Similar to {@link Integer#valueOf(String)} except it caches the result in + * a local LRU cache of 100 elements, organized by access order. + *

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

+ * This method MUST be used in the gnu.java.security and gnu.javax.crypto + * packages to ensure they would work with a version 1.4 only of the Java + * class library API. + * + * @param anInt a decimal integer. + * @return the {@link Integer} object representing the designated primitive. + */ + public static final Integer valueOf(int anInt) + { + return valueOf(Integer.toString(anInt, 10)); + } +} diff --git a/libjava/classpath/gnu/java/security/util/PRNG.java b/libjava/classpath/gnu/java/security/util/PRNG.java new file mode 100644 index 000000000..1bed04dcd --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/PRNG.java @@ -0,0 +1,141 @@ +/* PRNG.java -- A Utility methods for default source of randomness + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import java.util.HashMap; + +import gnu.java.security.prng.IRandom; +import gnu.java.security.prng.LimitReachedException; +import gnu.java.security.prng.MDGenerator; + +/** + * A useful hash-based (SHA) pseudo-random number generator used throughout this + * library. + * + * @see MDGenerator + */ +public class PRNG +{ + /** The underlying {@link IRandom}. */ + private IRandom delegate; + + /** + * Private constructor to enforce using the Factory method. + * + * @param delegate the undelying {@link IRandom} object used. + */ + private PRNG(IRandom delegate) + { + super(); + + this.delegate = delegate; + } + + public static final PRNG getInstance() + { + IRandom delegate = new MDGenerator(); + try + { + HashMap map = new HashMap(); + // initialise it with a seed + long t = System.currentTimeMillis(); + byte[] seed = new byte[] { + (byte)(t >>> 56), (byte)(t >>> 48), + (byte)(t >>> 40), (byte)(t >>> 32), + (byte)(t >>> 24), (byte)(t >>> 16), + (byte)(t >>> 8), (byte) t }; + map.put(MDGenerator.SEEED, seed); + delegate.init(map); // default is to use SHA-1 hash + } + catch (Exception x) + { + throw new ExceptionInInitializerError(x); + } + return new PRNG(delegate); + } + + /** + * Completely fills the designated buffer with random data + * generated by the underlying delegate. + * + * @param buffer the place holder of random bytes generated by the underlying + * delegate. On output, the contents of buffer are + * replaced with pseudo-random data, iff the buffer + * size is not zero. + */ + public void nextBytes(byte[] buffer) + { + nextBytes(buffer, 0, buffer.length); + } + + /** + * Fills the designated buffer, starting from byte at position + * offset with, at most, length bytes of random + * data generated by the underlying delegate. + * + * @see IRandom#nextBytes + */ + public void nextBytes(byte[] buffer, int offset, int length) + { + try + { + delegate.nextBytes(buffer, offset, length); + } + catch (LimitReachedException x) // re-initialise with a seed + { + try + { + HashMap map = new HashMap(); + long t = System.currentTimeMillis(); + byte[] seed = new byte[] { + (byte)(t >>> 56), (byte)(t >>> 48), + (byte)(t >>> 40), (byte)(t >>> 32), + (byte)(t >>> 24), (byte)(t >>> 16), + (byte)(t >>> 8), (byte) t }; + map.put(MDGenerator.SEEED, seed); + delegate.init(map); // default is to use SHA-1 hash + delegate.nextBytes(buffer, offset, length); + } + catch (Exception y) + { + throw new ExceptionInInitializerError(y); + } + } + } +} diff --git a/libjava/classpath/gnu/java/security/util/Prime.java b/libjava/classpath/gnu/java/security/util/Prime.java new file mode 100644 index 000000000..82c584ff4 --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/Prime.java @@ -0,0 +1,164 @@ +/* Prime.java --- Prime number generation utilities + Copyright (C) 1999, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; +import java.math.BigInteger; +import java.util.Random; +//import java.security.SecureRandom; + +public final class Prime +{ + + /* + See IEEE P1363 A.15.4 (10/05/98 Draft) + */ + public static BigInteger generateRandomPrime( int pmin, int pmax, BigInteger f ) + { + BigInteger d; + + //Step 1 - generate prime + BigInteger p = new BigInteger( (pmax + pmin)/2, new Random() ); + if( p.compareTo( BigInteger.valueOf( 1 ).shiftLeft( pmin ) ) <= 0 ) + { + p = p.add( BigInteger.valueOf( 1 ).shiftLeft( pmin ).subtract( p ) ); + } + + //Step 2 - test for even + if( p.mod( BigInteger.valueOf(2) ).compareTo( BigInteger.valueOf( 0 )) == 0) + p = p.add( BigInteger.valueOf( 1 ) ); + + for(;;) + { + //Step 3 + if( p.compareTo( BigInteger.valueOf( 1 ).shiftLeft( pmax)) > 0) + { + //Step 3.1 + p = p.subtract( BigInteger.valueOf( 1 ).shiftLeft( pmax) ); + p = p.add( BigInteger.valueOf( 1 ).shiftLeft( pmin) ); + p = p.subtract( BigInteger.valueOf( 1 ) ); + + //Step 3.2 + // put step 2 code here so looping code is cleaner + //Step 2 - test for even + if( p.mod( BigInteger.valueOf(2) ).compareTo( BigInteger.valueOf( 0 )) == 0) + p = p.add( BigInteger.valueOf( 1 ) ); + continue; + } + + //Step 4 - compute GCD + d = p.subtract( BigInteger.valueOf(1) ); + d = d.gcd( f ); + + //Step 5 - test d + if( d.compareTo( BigInteger.valueOf( 1 ) ) == 0) + { + //Step 5.1 - test primality + if( p.isProbablePrime( 1 ) == true ) + { + //Step 5.2; + return p; + } + } + //Step 6 + p = p.add( BigInteger.valueOf( 2 ) ); + + //Step 7 + } + } + + + /* + See IEEE P1363 A.15.5 (10/05/98 Draft) + */ + public static BigInteger generateRandomPrime( BigInteger r, BigInteger a, int pmin, int pmax, BigInteger f ) + { + BigInteger d, w; + + //Step 1 - generate prime + BigInteger p = new BigInteger( (pmax + pmin)/2, new Random() ); + + steptwo:{ //Step 2 + w = p.mod( r.multiply( BigInteger.valueOf(2) )); + + //Step 3 + p = p.add( r.multiply( BigInteger.valueOf(2) ) ); + p = p.subtract( w ); + p = p.add(a); + + //Step 4 - test for even + if( p.mod( BigInteger.valueOf(2) ).compareTo( BigInteger.valueOf( 0 )) == 0) + p = p.add( r ); + + for(;;) + { + //Step 5 + if( p.compareTo( BigInteger.valueOf( 1 ).shiftLeft( pmax)) > 0) + { + //Step 5.1 + p = p.subtract( BigInteger.valueOf( 1 ).shiftLeft( pmax) ); + p = p.add( BigInteger.valueOf( 1 ).shiftLeft( pmin) ); + p = p.subtract( BigInteger.valueOf( 1 ) ); + + //Step 5.2 - goto to Step 2 + break steptwo; + } + + //Step 6 + d = p.subtract( BigInteger.valueOf(1) ); + d = d.gcd( f ); + + //Step 7 - test d + if( d.compareTo( BigInteger.valueOf( 1 ) ) == 0) + { + //Step 7.1 - test primality + if( p.isProbablePrime( 1 ) == true ) + { + //Step 7.2; + return p; + } + } + //Step 8 + p = p.add( r.multiply( BigInteger.valueOf(2) ) ); + + //Step 9 + } + } + //Should never reach here but makes the compiler happy + return BigInteger.valueOf(0); + } +} diff --git a/libjava/classpath/gnu/java/security/util/Sequence.java b/libjava/classpath/gnu/java/security/util/Sequence.java new file mode 100644 index 000000000..63086d2bd --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/Sequence.java @@ -0,0 +1,133 @@ +/* Sequence.java -- a sequence of integers. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.util; + +import java.util.AbstractList; +import java.util.LinkedList; + +/** + * A monotonic sequence of integers in the finite field 232. + */ +public final class Sequence + extends AbstractList +{ + private final Integer[] sequence; + + /** + * Create a sequence of integers from 0 to end, with an increment of + * 1. If end is less than 0, then the sequence will wrap around + * through all positive integers then negative integers until the end value is + * reached. Naturally, this will result in an enormous object, so don't do + * this. + * + * @param end The ending value. + */ + public Sequence(int end) + { + this(0, end, 1); + } + + /** + * Create a sequence of integers from start to end, with an + * increment of 1. If end is less than start, then the + * sequence will wrap around until the end value is reached. Naturally, this + * will result in an enormous object, so don't do this. + * + * @param start The starting value. + * @param end The ending value. + */ + public Sequence(int start, int end) + { + this(start, end, 1); + } + + /** + * Create a sequence of integers from start to end, with an + * increment of span. If end is less than start, then + * the sequence will wrap around until the end value is reached. Naturally, + * this will result in an enormous object, so don't do this. + *

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

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

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

+   * toString(ba, 0, ba.length);
+   * 
+ * + * @param ba the byte array to convert. + * @return a string of hexadecimal characters (two for each byte) representing + * the designated input byte array. + */ + public static String toString(byte[] ba) + { + return toString(ba, 0, ba.length); + } + + /** + * Returns a string of hexadecimal digits from a byte array, starting at + * offset and consisting of length bytes. Each + * byte is converted to 2 hex symbols; zero(es) included. + * + * @param ba the byte array to convert. + * @param offset the index from which to start considering the bytes to + * convert. + * @param length the count of bytes, starting from the designated offset to + * convert. + * @return a string of hexadecimal characters (two for each byte) representing + * the designated input byte sub-array. + */ + public static final String toString(byte[] ba, int offset, int length) + { + char[] buf = new char[length * 2]; + for (int i = 0, j = 0, k; i < length;) + { + k = ba[offset + i++]; + buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F]; + buf[j++] = HEX_DIGITS[ k & 0x0F]; + } + return new String(buf); + } + + /** + * Returns a string of hexadecimal digits from a byte array. Each byte is + * converted to 2 hex symbols; zero(es) included. The argument is treated as a + * large little-endian integer and is returned as a large big-endian integer. + *

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

+   * toReversedString(ba, 0, ba.length);
+   * 
+ * + * @param ba the byte array to convert. + * @return a string of hexadecimal characters (two for each byte) representing + * the designated input byte array. + */ + public static String toReversedString(byte[] ba) + { + return toReversedString(ba, 0, ba.length); + } + + /** + * Returns a string of hexadecimal digits from a byte array, starting at + * offset and consisting of length bytes. Each + * byte is converted to 2 hex symbols; zero(es) included. + *

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

+ * Returns a byte array from a string of hexadecimal digits. + *

+ * + * @param s a string of hexadecimal ASCII characters + * @return the decoded byte array from the input hexadecimal string. + */ + public static byte[] toBytesFromString(String s) + { + int limit = s.length(); + byte[] result = new byte[((limit + 1) / 2)]; + int i = 0, j = 0; + if ((limit % 2) == 1) + result[j++] = (byte) fromDigit(s.charAt(i++)); + while (i < limit) + { + result[j ] = (byte) (fromDigit(s.charAt(i++)) << 4); + result[j++] |= (byte) fromDigit(s.charAt(i++)); + } + return result; + } + + /** + * Returns a byte array from a string of hexadecimal digits, interpreting them + * as a large big-endian integer and returning it as a large little-endian + * integer. + * + * @param s a string of hexadecimal ASCII characters + * @return the decoded byte array from the input hexadecimal string. + */ + public static byte[] toReversedBytesFromString(String s) + { + int limit = s.length(); + byte[] result = new byte[((limit + 1) / 2)]; + int i = 0; + if ((limit % 2) == 1) + result[i++] = (byte) fromDigit(s.charAt(--limit)); + while (limit > 0) + { + result[i ] = (byte) fromDigit(s.charAt(--limit)); + result[i++] |= (byte) (fromDigit(s.charAt(--limit)) << 4); + } + return result; + } + + /** + * Returns a number from 0 to 15 corresponding + * to the designated hexadecimal digit. + * + * @param c a hexadecimal ASCII symbol. + */ + public static int fromDigit(char c) + { + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else + throw new IllegalArgumentException("Invalid hexadecimal digit: " + c); + } + + /** + * Returns a string of 8 hexadecimal digits (most significant digit first) + * corresponding to the unsigned integer n. + * + * @param n the unsigned integer to convert. + * @return a hexadecimal string 8-character long. + */ + public static String toString(int n) + { + char[] buf = new char[8]; + for (int i = 7; i >= 0; i--) + { + buf[i] = HEX_DIGITS[n & 0x0F]; + n >>>= 4; + } + return new String(buf); + } + + /** + * Returns a string of hexadecimal digits from an integer array. Each int is + * converted to 4 hex symbols. + */ + public static String toString(int[] ia) + { + int length = ia.length; + char[] buf = new char[length * 8]; + for (int i = 0, j = 0, k; i < length; i++) + { + k = ia[i]; + buf[j++] = HEX_DIGITS[(k >>> 28) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 24) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 20) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 16) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 12) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 8) & 0x0F]; + buf[j++] = HEX_DIGITS[(k >>> 4) & 0x0F]; + buf[j++] = HEX_DIGITS[ k & 0x0F]; + } + return new String(buf); + } + + /** + * Returns a string of 16 hexadecimal digits (most significant digit first) + * corresponding to the unsigned long n. + * + * @param n the unsigned long to convert. + * @return a hexadecimal string 16-character long. + */ + public static String toString(long n) + { + char[] b = new char[16]; + for (int i = 15; i >= 0; i--) + { + b[i] = HEX_DIGITS[(int)(n & 0x0FL)]; + n >>>= 4; + } + return new String(b); + } + + /** + * Similar to the toString() method except that the Unicode + * escape character is inserted before every pair of bytes. Useful to + * externalise byte arrays that will be constructed later from such strings; + * eg. s-box values. + * + * @throws ArrayIndexOutOfBoundsException if the length is odd. + */ + public static String toUnicodeString(byte[] ba) + { + return toUnicodeString(ba, 0, ba.length); + } + + /** + * Similar to the toString() method except that the Unicode + * escape character is inserted before every pair of bytes. Useful to + * externalise byte arrays that will be constructed later from such strings; + * eg. s-box values. + * + * @throws ArrayIndexOutOfBoundsException if the length is odd. + */ + public static final String toUnicodeString(byte[] ba, int offset, int length) + { + CPStringBuilder sb = new CPStringBuilder(); + int i = 0; + int j = 0; + int k; + sb.append('\n').append("\""); + while (i < length) + { + sb.append("\\u"); + k = ba[offset + i++]; + sb.append(HEX_DIGITS[(k >>> 4) & 0x0F]); + sb.append(HEX_DIGITS[ k & 0x0F]); + k = ba[offset + i++]; + sb.append(HEX_DIGITS[(k >>> 4) & 0x0F]); + sb.append(HEX_DIGITS[ k & 0x0F]); + if ((++j % 8) == 0) + sb.append("\"+").append('\n').append("\""); + } + sb.append("\"").append('\n'); + return sb.toString(); + } + + /** + * Similar to the toString() method except that the Unicode + * escape character is inserted before every pair of bytes. Useful to + * externalise integer arrays that will be constructed later from such + * strings; eg. s-box values. + * + * @throws ArrayIndexOutOfBoundsException if the length is not a multiple of + * 4. + */ + public static String toUnicodeString(int[] ia) + { + CPStringBuilder sb = new CPStringBuilder(); + int i = 0; + int j = 0; + int k; + sb.append('\n').append("\""); + while (i < ia.length) + { + k = ia[i++]; + sb.append("\\u"); + sb.append(HEX_DIGITS[(k >>> 28) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 24) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 20) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 16) & 0x0F]); + sb.append("\\u"); + sb.append(HEX_DIGITS[(k >>> 12) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 8) & 0x0F]); + sb.append(HEX_DIGITS[(k >>> 4) & 0x0F]); + sb.append(HEX_DIGITS[ k & 0x0F]); + if ((++j % 4) == 0) + sb.append("\"+").append('\n').append("\""); + } + sb.append("\"").append('\n'); + return sb.toString(); + } + + public static byte[] toBytesFromUnicode(String s) + { + int limit = s.length() * 2; + byte[] result = new byte[limit]; + char c; + for (int i = 0; i < limit; i++) + { + c = s.charAt(i >>> 1); + result[i] = (byte)(((i & 1) == 0) ? c >>> 8 : c); + } + return result; + } + + /** + * Dumps a byte array as a string, in a format that is easy to read for + * debugging. The string m is prepended to the start of each + * line. + *

+ * If offset and length are omitted, the whole + * array is used. If m is omitted, nothing is prepended to each + * line. + * + * @param data the byte array to be dumped. + * @param offset the offset within data to start from. + * @param length the number of bytes to dump. + * @param m a string to be prepended to each line. + * @return a string containing the result. + */ + public static String dumpString(byte[] data, int offset, int length, String m) + { + if (data == null) + return m + "null\n"; + CPStringBuilder sb = new CPStringBuilder(length * 3); + if (length > 32) + sb.append(m).append("Hexadecimal dump of ") + .append(length).append(" bytes...\n"); + // each line will list 32 bytes in 4 groups of 8 each + int end = offset + length; + String s; + int l = Integer.toString(length).length(); + if (l < 4) + l = 4; + for (; offset < end; offset += 32) + { + if (length > 32) + { + s = " " + offset; + sb.append(m).append(s.substring(s.length() - l)).append(": "); + } + int i = 0; + for (; i < 32 && offset + i + 7 < end; i += 8) + sb.append(toString(data, offset + i, 8)).append(' '); + if (i < 32) + for (; i < 32 && offset + i < end; i++) + sb.append(byteToString(data[offset + i])); + sb.append('\n'); + } + return sb.toString(); + } + + public static String dumpString(byte[] data) + { + return (data == null) ? "null\n" : dumpString(data, 0, data.length, ""); + } + + public static String dumpString(byte[] data, String m) + { + return (data == null) ? "null\n" : dumpString(data, 0, data.length, m); + } + + public static String dumpString(byte[] data, int offset, int length) + { + return dumpString(data, offset, length, ""); + } + + /** + * Returns a string of 2 hexadecimal digits (most significant digit first) + * corresponding to the lowest 8 bits of n. + * + * @param n the byte value to convert. + * @return a string of 2 hex characters representing the input. + */ + public static String byteToString(int n) + { + char[] buf = { HEX_DIGITS[(n >>> 4) & 0x0F], HEX_DIGITS[n & 0x0F] }; + return new String(buf); + } + + /** + * Converts a designated byte array to a Base-64 representation, with the + * exceptions that (a) leading 0-byte(s) are ignored, and (b) the character + * '.' (dot) shall be used instead of "+' (plus). + *

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

+ * Converts a string representing the encoding of some bytes in Base-64 to + * their original form. + * + * @param str the Base-64 encoded representation of some byte(s). + * @return the bytes represented by the str. + * @throws NumberFormatException if str is null, + * or str contains an illegal Base-64 character. + * @see #toBase64(byte[]) + */ + public static final byte[] fromBase64(String str) + { + int len = str.length(); + if (len == 0) + throw new NumberFormatException("Empty string"); + byte[] a = new byte[len + 1]; + int i, j; + for (i = 0; i < len; i++) + try + { + a[i] = (byte) BASE64_CHARS.indexOf(str.charAt(i)); + } + catch (ArrayIndexOutOfBoundsException x) + { + throw new NumberFormatException("Illegal character at #" + i); + } + i = len - 1; + j = len; + try + { + while (true) + { + a[j] = a[i]; + if (--i < 0) + break; + a[j] |= (a[i] & 0x03) << 6; + j--; + a[j] = (byte)((a[i] & 0x3C) >>> 2); + if (--i < 0) + break; + a[j] |= (a[i] & 0x0F) << 4; + j--; + a[j] = (byte)((a[i] & 0x30) >>> 4); + if (--i < 0) + break; + a[j] |= (a[i] << 2); + j--; + a[j] = 0; + if (--i < 0) + break; + } + } + catch (Exception ignored) + { + } + try + { // ignore leading 0-bytes + while (a[j] == 0) + j++; + } + catch (Exception x) + { + return new byte[1]; // one 0-byte + } + byte[] result = new byte[len - j + 1]; + System.arraycopy(a, j, result, 0, len - j + 1); + return result; + } + + // BigInteger utilities ---------------------------------------------------- + + /** + * Treats the input as the MSB representation of a number, and discards + * leading zero elements. For efficiency, the input is simply returned if no + * leading zeroes are found. + * + * @param n the {@link BigInteger} to trim. + * @return the byte array representation of the designated {@link BigInteger} + * with no leading 0-bytes. + */ + public static final byte[] trim(BigInteger n) + { + byte[] in = n.toByteArray(); + if (in.length == 0 || in[0] != 0) + return in; + int len = in.length; + int i = 1; + while (in[i] == 0 && i < len) + ++i; + byte[] result = new byte[len - i]; + System.arraycopy(in, i, result, 0, len - i); + return result; + } + + /** + * Returns a hexadecimal dump of the trimmed bytes of a {@link BigInteger}. + * + * @param x the {@link BigInteger} to display. + * @return the string representation of the designated {@link BigInteger}. + */ + public static final String dump(BigInteger x) + { + return dumpString(trim(x)); + } +} diff --git a/libjava/classpath/gnu/java/security/util/package.html b/libjava/classpath/gnu/java/security/util/package.html new file mode 100644 index 000000000..36dd33b79 --- /dev/null +++ b/libjava/classpath/gnu/java/security/util/package.html @@ -0,0 +1,46 @@ + + + + +GNU Classpath - gnu.java.security.util + + +

+ + + diff --git a/libjava/classpath/gnu/java/security/x509/GnuPKIExtension.java b/libjava/classpath/gnu/java/security/x509/GnuPKIExtension.java new file mode 100644 index 000000000..8e74b8b24 --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/GnuPKIExtension.java @@ -0,0 +1,59 @@ +/* GnuPKIExtension.java -- interface for GNU PKI extensions. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509; + +import gnu.java.security.OID; +import gnu.java.security.x509.ext.Extension; + +import java.security.cert.X509Extension; +import java.util.Collection; + +public interface GnuPKIExtension extends X509Extension +{ + + /** + * Returns the extension object for the given object identifier. + * + * @param oid The OID of the extension to get. + * @return The extension, or null if there is no such extension. + */ + Extension getExtension(OID oid); + + Collection getExtensions(); +} diff --git a/libjava/classpath/gnu/java/security/x509/PolicyNodeImpl.java b/libjava/classpath/gnu/java/security/x509/PolicyNodeImpl.java new file mode 100644 index 000000000..60d35574d --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/PolicyNodeImpl.java @@ -0,0 +1,216 @@ +/* PolicyNodeImpl.java -- An implementation of a policy tree node. + Copyright (C) 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509; + +import gnu.java.lang.CPStringBuilder; + +import java.security.cert.PolicyNode; +import java.security.cert.PolicyQualifierInfo; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +public final class PolicyNodeImpl implements PolicyNode +{ + + // Fields. + // ------------------------------------------------------------------------- + + private String policy; + private final Set expectedPolicies; + private final Set qualifiers; + private final Set children; + private PolicyNodeImpl parent; + private int depth; + private boolean critical; + private boolean readOnly; + + // Constructors. + // ------------------------------------------------------------------------- + + public PolicyNodeImpl() + { + expectedPolicies = new HashSet(); + qualifiers = new HashSet(); + children = new HashSet(); + readOnly = false; + critical = false; + } + + // Instance methods. + // ------------------------------------------------------------------------- + + public void addChild(PolicyNodeImpl node) + { + if (readOnly) + throw new IllegalStateException("read only"); + if (node.getParent() != null) + throw new IllegalStateException("already a child node"); + node.parent = this; + node.setDepth(depth + 1); + children.add(node); + } + + public Iterator getChildren() + { + return Collections.unmodifiableSet(children).iterator(); + } + + public int getDepth() + { + return depth; + } + + public void setDepth(int depth) + { + if (readOnly) + throw new IllegalStateException("read only"); + this.depth = depth; + } + + public void addAllExpectedPolicies(Set policies) + { + if (readOnly) + throw new IllegalStateException("read only"); + expectedPolicies.addAll(policies); + } + + public void addExpectedPolicy(String policy) + { + if (readOnly) + throw new IllegalStateException("read only"); + expectedPolicies.add(policy); + } + + public Set getExpectedPolicies() + { + return Collections.unmodifiableSet(expectedPolicies); + } + + public PolicyNode getParent() + { + return parent; + } + + public void addAllPolicyQualifiers (Collection qualifiers) + { + for (Iterator it = qualifiers.iterator(); it.hasNext(); ) + { + if (!(it.next() instanceof PolicyQualifierInfo)) + throw new IllegalArgumentException ("can only add PolicyQualifierInfos"); + } + qualifiers.addAll (qualifiers); + } + + public void addPolicyQualifier (PolicyQualifierInfo qualifier) + { + if (readOnly) + throw new IllegalStateException("read only"); + qualifiers.add(qualifier); + } + + public Set getPolicyQualifiers() + { + return Collections.unmodifiableSet(qualifiers); + } + + public String getValidPolicy() + { + return policy; + } + + public void setValidPolicy(String policy) + { + if (readOnly) + throw new IllegalStateException("read only"); + this.policy = policy; + } + + public boolean isCritical() + { + return critical; + } + + public void setCritical(boolean critical) + { + if (readOnly) + throw new IllegalStateException("read only"); + this.critical = critical; + } + + public void setReadOnly() + { + if (readOnly) + return; + readOnly = true; + for (Iterator it = getChildren(); it.hasNext(); ) + ((PolicyNodeImpl) it.next()).setReadOnly(); + } + + public String toString() + { + CPStringBuilder buf = new CPStringBuilder(); + for (int i = 0; i < depth; i++) + buf.append(" "); + buf.append("("); + buf.append(PolicyNodeImpl.class.getName()); + buf.append(" (oid "); + buf.append(policy); + buf.append(") (depth "); + buf.append(depth); + buf.append(") (qualifiers "); + buf.append(qualifiers); + buf.append(") (critical "); + buf.append(critical); + buf.append(") (expectedPolicies "); + buf.append(expectedPolicies); + buf.append(") (children ("); + final String nl = System.getProperty("line.separator"); + for (Iterator it = getChildren(); it.hasNext(); ) + { + buf.append(nl); + buf.append(it.next().toString()); + } + buf.append(")))"); + return buf.toString(); + } +} diff --git a/libjava/classpath/gnu/java/security/x509/Util.java b/libjava/classpath/gnu/java/security/x509/Util.java new file mode 100644 index 000000000..7b6c89f6a --- /dev/null +++ b/libjava/classpath/gnu/java/security/x509/Util.java @@ -0,0 +1,204 @@ +/* Util.java -- Miscellaneous utility methods. + Copyright (C) 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.security.x509; + +import gnu.java.lang.CPStringBuilder; + +/** + * A collection of useful class methods. + * + * @author Casey Marshall (rsdio@metastatic.org) + */ +public final class Util +{ + + // Constants. + // ------------------------------------------------------------------------- + + public static final String HEX = "0123456789abcdef"; + + // Class methods. + // ------------------------------------------------------------------------- + + /** + * Convert a byte array to a hexadecimal string, as though it were a + * big-endian arbitrarily-sized integer. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to format. + * @return A hexadecimal representation of the specified bytes. + */ + public static String toHexString(byte[] buf, int off, int len) + { + CPStringBuilder str = new CPStringBuilder(); + for (int i = 0; i < len; i++) + { + str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F)); + str.append(HEX.charAt(buf[i+off] & 0x0F)); + } + return str.toString(); + } + + /** + * See {@link #toHexString(byte[],int,int)}. + */ + public static String toHexString(byte[] buf) + { + return Util.toHexString(buf, 0, buf.length); + } + + /** + * Convert a byte array to a hexadecimal string, separating octets + * with the given character. + * + * @param buf The bytes to format. + * @param off The offset to start at. + * @param len The number of bytes to format. + * @param sep The character to insert between octets. + * @return A hexadecimal representation of the specified bytes. + */ + public static String toHexString(byte[] buf, int off, int len, char sep) + { + CPStringBuilder str = new CPStringBuilder(); + for (int i = 0; i < len; i++) + { + str.append(HEX.charAt(buf[i+off] >>> 4 & 0x0F)); + str.append(HEX.charAt(buf[i+off] & 0x0F)); + if (i < len - 1) + str.append(sep); + } + return str.toString(); + } + + /** + * See {@link #toHexString(byte[],int,int,char)}. + */ + public static String toHexString(byte[] buf, char sep) + { + return Util.toHexString(buf, 0, buf.length, sep); + } + + /** + * Create a representation of the given byte array similar to the + * output of `hexdump -C', which is + * + *

OFFSET  SIXTEEN-BYTES-IN-HEX  PRINTABLE-BYTES
+ * + *

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

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

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

+ + + diff --git a/libjava/classpath/gnu/java/util/Base64.java b/libjava/classpath/gnu/java/util/Base64.java new file mode 100644 index 000000000..80b1fcc02 --- /dev/null +++ b/libjava/classpath/gnu/java/util/Base64.java @@ -0,0 +1,342 @@ +/* Base64.java -- Base64 encoding and decoding. + Copyright (C) 2006, 2007 Free Software Foundation, Inc. + +This file is a part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or (at +your option) any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +USA + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. + +-- +Base64 encoding derived from ISC's DHCP. Copyright notices from DHCP +follow. See http://www.isc.org/products/DHCP/. + +Copyright (c) 1996 by Internet Software Consortium. + +Permission to use, copy, modify, and distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM +DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL +INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING +FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION +WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +-- +Portions Copyright (c) 1995 by International Business Machines, Inc. + +International Business Machines, Inc. (hereinafter called IBM) grants +permission under its copyrights to use, copy, modify, and distribute +this Software with or without fee, provided that the above copyright +notice and all paragraphs of this notice appear in all copies, and +that the name of IBM not be used in connection with the marketing of +any product incorporating the Software or modifications thereof, +without specific, written prior permission. + +To the extent it has a right to do so, IBM grants an immunity from +suit under its patents, if any, for the use, sale or manufacture of +products to the extent that such products are used for performing +Domain Name System dynamic updates in TCP/IP networks by means of the +Software. No immunity is granted for any product per se or for any +other function of any product. + +THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, +DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE, EVEN IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH +DAMAGES. */ + + +package gnu.java.util; + +import gnu.java.lang.CPStringBuilder; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; + +public final class Base64 +{ + + // No constructor. + private Base64() { } + + // Class methods. + // ------------------------------------------------------------------------- + + /** Base-64 characters. */ + private static final String BASE_64 = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + /** Base-64 padding character. */ + private static final char BASE_64_PAD = '='; + + /** + * Base64 encode a byte array, with no line wrapping. + * + * @param buf The byte array to encode. + * @return buf encoded in Base64. + */ + public static String encode(byte[] buf) + { + return encode(buf, 0); + } + + /** + * Base64 encode a byte array, returning the returning string. + * + * @param buf The byte array to encode. + * @param tw The total length of any line, 0 for unlimited. + * @return buf encoded in Base64. + */ + public static String encode(byte[] buf, int tw) + { + return encode(buf, 0, buf.length, tw); + } + + /** + * Base64 encode a byte array, returning the returning string. + * + * @param buf The byte array to encode. + * @param offset The offset in the byte array to start. + * @param length The number of bytes to encode. + * @param tw The total length of any line, 0 for unlimited. + * @return buf encoded in Base64. + */ + public static String encode(byte[] buf, int offset, int length, int tw) + { + if (offset < 0 || length < 0 || offset + length > buf.length) + throw new ArrayIndexOutOfBoundsException(buf.length + " " + + offset + " " + + length); + int srcLength = buf.length - offset; + byte[] input = new byte[3]; + int[] output = new int[4]; + CPStringBuilder out = new CPStringBuilder(); + int i = offset; + int chars = 0; + + while (srcLength > 2) + { + input[0] = buf[i++]; + input[1] = buf[i++]; + input[2] = buf[i++]; + srcLength -= 3; + + output[0] = (input[0] & 0xff) >>> 2; + output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4); + output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6); + output[3] = input[2] & 0x3f; + + out.append(BASE_64.charAt(output[0])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[1])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[2])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[3])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + } + + if (srcLength != 0) + { + input[0] = input[1] = input[2] = 0; + for (int j = 0; j < srcLength; j++) + { + input[j] = buf[i+j]; + } + output[0] = (input[0] & 0xff) >>> 2; + output[1] = ((input[0] & 0x03) << 4) + ((input[1] & 0xff) >>> 4); + output[2] = ((input[1] & 0x0f) << 2) + ((input[2] & 0xff) >>> 6); + + out.append(BASE_64.charAt(output[0])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64.charAt(output[1])); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + if (srcLength == 1) + { + out.append(BASE_64_PAD); + } + else + { + out.append(BASE_64.charAt(output[2])); + } + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + out.append(BASE_64_PAD); + if (tw > 0 && ++chars % tw == 0) + { + out.append("\n"); + } + } + if (tw > 0) + { + out.append("\n"); + } + + return out.toString(); + } + + /** + * Decode a Base-64 string into a byte array. + * + * @param b64 The Base-64 encoded string. + * @return The decoded bytes. + * @throws java.io.IOException If the argument is not a valid Base-64 + * encoding. + */ + public static byte[] decode(String b64) throws IOException + { + ByteArrayOutputStream result = new ByteArrayOutputStream(b64.length() / 3); + int state = 0, i; + byte temp = 0; + + for (i = 0; i < b64.length(); i++) + { + if (Character.isWhitespace(b64.charAt(i))) + { + continue; + } + if (b64.charAt(i) == BASE_64_PAD) + { + break; + } + + int pos = BASE_64.indexOf(b64.charAt(i)); + if (pos < 0) + { + throw new IOException("non-Base64 character " + b64.charAt(i)); + } + switch (state) + { + case 0: + temp = (byte) (pos - BASE_64.indexOf('A') << 2); + state = 1; + break; + + case 1: + temp |= (byte) (pos - BASE_64.indexOf('A') >>> 4); + result.write(temp); + temp = (byte) ((pos - BASE_64.indexOf('A') & 0x0f) << 4); + state = 2; + break; + + case 2: + temp |= (byte) ((pos - BASE_64.indexOf('A') & 0x7f) >>> 2); + result.write(temp); + temp = (byte) ((pos - BASE_64.indexOf('A') & 0x03) << 6); + state = 3; + break; + + case 3: + temp |= (byte) (pos - BASE_64.indexOf('A') & 0xff); + result.write(temp); + state = 0; + break; + + default: + throw new Error("this statement should be unreachable"); + } + } + + if (i < b64.length() && b64.charAt(i) == BASE_64_PAD) + { + switch (state) + { + case 0: + case 1: + throw new IOException("malformed Base64 sequence"); + + case 2: + i++; + for ( ; i < b64.length(); i++) + { + if (!Character.isWhitespace(b64.charAt(i))) + { + break; + } + } + // We must see a second pad character here. + if (b64.charAt(i) != BASE_64_PAD) + { + throw new IOException("malformed Base64 sequence"); + } + i++; + // Fall-through. + + case 3: + i++; + for ( ; i < b64.length(); i++) + { + // We should only see whitespace after this. + if (!Character.isWhitespace(b64.charAt(i))) + { + throw new IOException("malformed Base64 sequence"); + } + } + } + } + else + { + if (state != 0) + { + throw new IOException("malformed Base64 sequence"); + } + } + + return result.toByteArray(); + } +} diff --git a/libjava/classpath/gnu/java/util/DoubleEnumeration.java b/libjava/classpath/gnu/java/util/DoubleEnumeration.java new file mode 100644 index 000000000..852644bc6 --- /dev/null +++ b/libjava/classpath/gnu/java/util/DoubleEnumeration.java @@ -0,0 +1,138 @@ +/* gnu.java.util.DoubleEnumeration + Copyright (C) 1998, 1999, 2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.util; + +import java.util.Enumeration; +import java.util.NoSuchElementException; + + +/** + * This is a helper class that combines two Enumerations. + * It returns the elements of the first Enumeration until it has + * no more elements and then returns the elements of the second + * Enumeration.
+ * + * In the default case: + *
+ * doubleEnum = new DoubleEnumeration(enum1, enum2);
+ * while (doubleEnum.hasMoreElements()) {
+ *    Object o = doubleEnum.nextElement();
+ *    do_something(o);
+ * }
+ * 
+ * it calls hasMoreElements of the Enumerations as few times as + * possible. + * The references to the Enumerations are cleared as soon as they have no + * more elements to help garbage collecting. + * + * @author Jochen Hoenicke + * @author Mark Wielaard (mark@klomp.org) + */ +public class DoubleEnumeration implements Enumeration +{ + /** + * This is true as long as one of the enumerations has more + * elements. + * Only valid when hasChecked is true. + * Set in hasMoreElements() + */ + private boolean hasMore; + /** + * This is true, if it is sure that hasMore indicates wether there are + * more elements. + * Set to true in hasMoreElements(). + * Set to false in getNextElement(). + */ + private boolean hasChecked; + /** + * The first enumeration. + */ + private Enumeration e1; + /** + * The second enumeration. + */ + private Enumeration e2; + + /** + * Creates a new Enumeration combining the given two enumerations. + * The enumerations mustn't be accessed by other classes. + */ + public DoubleEnumeration(Enumeration e1, Enumeration e2) + { + this.e1 = e1; + this.e2 = e2; + hasChecked = false; + } + + /** + * Returns true, if at least one of the two enumerations has more + * elements. + */ + public boolean hasMoreElements() + { + if (hasChecked) + return hasMore; + + hasMore = (e1 != null && e1.hasMoreElements()); + + if (!hasMore) { + e1 = e2; + e2 = null; + hasMore = (e1 != null && e1.hasMoreElements()); + } + + hasChecked = true; + return hasMore; + } + + /** + * Returns the next element. This returns the next element of the + * first enumeration, if it has more elements, otherwise the next + * element of the second enumeration. If both enumeration don't have + * any elements it throws a NoSuchElementException. + */ + public T nextElement() + { + if (!hasMoreElements()) + throw new NoSuchElementException(); + else { + hasChecked = false; + return e1.nextElement(); + } + } +} diff --git a/libjava/classpath/gnu/java/util/EmptyEnumeration.java b/libjava/classpath/gnu/java/util/EmptyEnumeration.java new file mode 100644 index 000000000..30c50d81d --- /dev/null +++ b/libjava/classpath/gnu/java/util/EmptyEnumeration.java @@ -0,0 +1,90 @@ +/* EmptyEnumeration.java -- a constant empty enumeration + Copyright (C) 2001, 2002 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.util; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.NoSuchElementException; + +/** + * This is a helper class that produces an empty Enumerations. There is only + * one instance of this class that can be used whenever one needs a + * non-null but empty enumeration. Using this class prevents multiple + * small objects and inner classes. getInstance() returns + * the only instance of this class. It can be shared by multiple objects and + * threads. + * + * @author Mark Wielaard (mark@klomp.org) + */ +public final class EmptyEnumeration implements Enumeration, Serializable +{ + /** The only instance of this class */ + private static final EmptyEnumeration instance = + new EmptyEnumeration(); + + /** + * Returns an instance of this class for Object. + * It can be shared by multiple objects and threads. + * + * @return the common empty enumeration + */ + public static EmptyEnumeration getInstance() + { + return instance; + } + + /** + * Returns false, since there are no elements. + * + * @return false + */ + public boolean hasMoreElements() + { + return false; + } + + /** + * Always throws NoSuchElementException, since it is empty. + * + * @throws NoSuchElementException this is empty + */ + public T nextElement() + { + throw new NoSuchElementException(); + } +} diff --git a/libjava/classpath/gnu/java/util/LRUCache.java b/libjava/classpath/gnu/java/util/LRUCache.java new file mode 100644 index 000000000..784a442ab --- /dev/null +++ b/libjava/classpath/gnu/java/util/LRUCache.java @@ -0,0 +1,77 @@ +/* LRUCache.java -- A LRU Cache implementation + Copyright (C) 2007 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.util; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * A least recently used cache, based on LinkedHashMap. + */ +public class LRUCache + extends LinkedHashMap +{ + + /** + * The capacity of the cache. + */ + private int capacity; + + /** + * Creates a new LRUCache instance with the specified capacity. + * + * @param cap the capacity of the new cache + */ + public LRUCache(int cap) + { + super(); + capacity = cap; + } + + /** + * Returns true when the oldest entry should be removed. + * + * @param eldest the entry about to be removed + * + * @return true when the oldest entry should be removed + */ + protected boolean removeEldestEntry(Map.Entry eldest) + { + return size() > capacity; + } +} diff --git a/libjava/classpath/gnu/java/util/WeakIdentityHashMap.java b/libjava/classpath/gnu/java/util/WeakIdentityHashMap.java new file mode 100644 index 000000000..4d9014969 --- /dev/null +++ b/libjava/classpath/gnu/java/util/WeakIdentityHashMap.java @@ -0,0 +1,862 @@ +/* WeakIdentityHashMap -- an identity hashtable that keeps only weak references + to its keys, allowing the virtual machine to reclaim them + Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.util; + +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.AbstractMap; +import java.util.AbstractSet; +import java.util.Collection; +import java.util.ConcurrentModificationException; +import java.util.Iterator; +import java.util.Map; +import java.util.NoSuchElementException; +import java.util.Set; + +/** + * A weak hash map has only weak references to the key. This means that it + * allows the key to be garbage collected if it is not used otherwise. If + * this happens, the entry will eventually disappear from the map, + * asynchronously. + * + *

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

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

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

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

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

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

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

+ + + diff --git a/libjava/classpath/gnu/java/util/regex/BacktrackStack.java b/libjava/classpath/gnu/java/util/regex/BacktrackStack.java new file mode 100644 index 000000000..b03fb8707 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/BacktrackStack.java @@ -0,0 +1,124 @@ +/* gnu/regexp/BacktrackStack.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + + +package gnu.java.util.regex; + +/** + * An instance of this class represents a stack + * used for backtracking. + * + * @author Ito Kazumitsu + */ +final class BacktrackStack +{ + + /** A set of data to be used for backtracking. */ + static class Backtrack + { + /** REToken to which to go back */ + REToken token; + /** CharIndexed on which matches are being searched for. */ + CharIndexed input; + /** REMatch to be used by the REToken token. */ + REMatch match; + /** Some parameter used by the token's backtrack method. */ + Object param; + Backtrack (REToken token, CharIndexed input, REMatch match, + Object param) + { + this.token = token; + this.input = input; + // REMatch may change before backtracking is needed. So we + // keep a clone of it. + this.match = (REMatch) match.clone (); + this.param = param; + } + } + + Backtrack[] stack; + private int size; + private int capacity; + private static final int INITIAL_CAPACITY = 32; + private static final int CAPACITY_INCREMENT = 16; + + BacktrackStack () + { + stack = new Backtrack[INITIAL_CAPACITY]; + size = 0; + capacity = INITIAL_CAPACITY; + } + + boolean empty () + { + return size == 0; + } + + Backtrack peek () + { + return stack[size - 1]; + } + + Backtrack pop () + { + Backtrack bt = stack[--size]; + stack[size] = null; + return bt; + } + + void clear () + { + for (int i = 0; i < size; i++) + { + stack[i] = null; + } + size = 0; + } + + void push (Backtrack bt) + { + if (size >= capacity) + { + capacity += CAPACITY_INCREMENT; + Backtrack[]newStack = new Backtrack[capacity]; + System.arraycopy (stack, 0, newStack, 0, size); + stack = newStack; + } + stack[size++] = bt; + } + +} diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexed.java b/libjava/classpath/gnu/java/util/regex/CharIndexed.java new file mode 100644 index 000000000..de4b1667f --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/CharIndexed.java @@ -0,0 +1,134 @@ +/* gnu/regexp/CharIndexed.java + Copyright (C) 1998-2001, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.util.regex; + +/** + * Defines the interface used internally so that different types of source + * text can be accessed in the same way. Built-in concrete classes provide + * support for String, StringBuffer, InputStream and char[] types. + * A class that is CharIndexed supports the notion of a cursor within a + * block of text. The cursor must be able to be advanced via the move() + * method. The charAt() method returns the character at the cursor position + * plus a given offset. + * + * @author Wes Biggs + */ +public interface CharIndexed +{ + /** + * Defines a constant (0xFFFF was somewhat arbitrarily chosen) + * that can be returned by the charAt() function indicating that + * the specified index is out of range. + */ + char OUT_OF_BOUNDS = '\uFFFF'; + + /** + * Returns the character at the given offset past the current cursor + * position in the input. The index of the current position is zero. + * It is possible for this method to be called with a negative index. + * This happens when using the '^' operator in multiline matching mode + * or the '\b' or '\<' word boundary operators. In any case, the lower + * bound is currently fixed at -2 (for '^' with a two-character newline). + * + * @param index the offset position in the character field to examine + * @return the character at the specified index, or the OUT_OF_BOUNDS + * character defined by this interface. + */ + char charAt (int index); + + /** + * Shifts the input buffer by a given number of positions. Returns + * true if the new cursor position is valid. + */ + boolean move (int index); + + /** + * Shifts the input buffer by a given number of positions. Returns + * true if the new cursor position is valid or cursor position is at + * the end of input. + */ + boolean move1 (int index); // I cannot think of a better name for this. + + /** + * Returns true if the most recent move() operation placed the cursor + * position at a valid position in the input. + */ + boolean isValid (); + + /** + * Returns another CharIndexed containing length characters to the left + * of the given index. The given length is an expected maximum and + * the returned CharIndexed may not necessarily contain so many characters. + */ + CharIndexed lookBehind (int index, int length); + + /** + * Returns the effective length of this CharIndexed + */ + int length (); + + /** + * Sets the REMatch last found on this input. + */ + void setLastMatch (REMatch match); + + /** + * Returns the REMatch last found on this input. + */ + REMatch getLastMatch (); + + /** + * Sets the information used for hitEnd(). + */ + void setHitEnd (REMatch match); + + /** + * Returns whether the matcher has hit the end of input. + */ + boolean hitEnd (); + + /** + * Returns the anchor. + */ + int getAnchor (); + + /** + * Sets the anchor. + */ + void setAnchor (int anchor); +} diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexedCharArray.java b/libjava/classpath/gnu/java/util/regex/CharIndexedCharArray.java new file mode 100644 index 000000000..565773837 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/CharIndexedCharArray.java @@ -0,0 +1,48 @@ +/* gnu/regexp/CharIndexedCharArray.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.util.regex; +import java.nio.CharBuffer; + +class CharIndexedCharArray extends CharIndexedCharSequence +{ + + CharIndexedCharArray (char[]str, int index) + { + super (CharBuffer.wrap (str), index); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java b/libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java new file mode 100644 index 000000000..bc3cbbd1d --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/CharIndexedCharSequence.java @@ -0,0 +1,119 @@ +/* gnu/regexp/CharIndexedCharSequence.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.util.regex; +import java.io.Serializable; + +class CharIndexedCharSequence implements CharIndexed, Serializable +{ + private CharSequence s; + private int anchor; + private int len; + + CharIndexedCharSequence (CharSequence s, int index) + { + this.s = s; + len = s.length (); + anchor = index; + } + + public char charAt (int index) + { + int pos = anchor + index; + return ((pos < len) && (pos >= 0)) ? s.charAt (pos) : OUT_OF_BOUNDS; + } + + public boolean isValid () + { + return (anchor < len); + } + + public boolean move (int index) + { + return ((anchor += index) < len); + } + + public boolean move1 (int index) + { + return ((anchor += index) <= len); + } + + public CharIndexed lookBehind (int index, int length) + { + if (length > (anchor + index)) + length = anchor + index; + return new CharIndexedCharSequence (s, anchor + index - length); + } + + public int length () + { + return len - anchor; + } + + private REMatch lastMatch; + public void setLastMatch (REMatch match) + { + lastMatch = (REMatch) match.clone (); + lastMatch.anchor = anchor; + } + public REMatch getLastMatch () + { + return lastMatch; + } + + private int rightmostTriedPosition = 0; + public void setHitEnd (REMatch match) + { + int pos = anchor + match.index; + if (pos > rightmostTriedPosition) + rightmostTriedPosition = pos; + } + public boolean hitEnd () + { + return rightmostTriedPosition >= len; + } + + public int getAnchor () + { + return anchor; + } + public void setAnchor (int anchor) + { + this.anchor = anchor; + } + +} diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java b/libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java new file mode 100644 index 000000000..d6340298a --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/CharIndexedInputStream.java @@ -0,0 +1,253 @@ +/* gnu/regexp/CharIndexedInputStream.java + Copyright (C) 1998-2001, 2004, 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.util.regex; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; + +// TODO: move(x) shouldn't rely on calling next() x times + +class CharIndexedInputStream implements CharIndexed +{ + private static final int BUFFER_INCREMENT = 1024; + private static final int UNKNOWN = Integer.MAX_VALUE; // value for end + + private BufferedInputStream br; + + // so that we don't try to reset() right away + private int index = -1; + + private int bufsize = BUFFER_INCREMENT; + + private int end = UNKNOWN; + + private char cached = OUT_OF_BOUNDS; + + // Big enough for a \r\n pair + // lookBehind[0] = most recent + // lookBehind[1] = second most recent + private char[] lookBehind = new char[]{ OUT_OF_BOUNDS, OUT_OF_BOUNDS }; + + CharIndexedInputStream (InputStream str, int index) + { + if (str instanceof BufferedInputStream) + br = (BufferedInputStream) str; + else + br = new BufferedInputStream (str, BUFFER_INCREMENT); + next (); + if (index > 0) + move (index); + } + + private boolean next () + { + if (end == 1) + return false; + end--; // closer to end + + try + { + if (index != -1) + { + br.reset (); + } + int i = br.read (); + br.mark (bufsize); + if (i == -1) + { + end = 1; + cached = OUT_OF_BOUNDS; + return false; + } + cached = (char) i; + index = 1; + } catch (IOException e) + { + e.printStackTrace (); + cached = OUT_OF_BOUNDS; + return false; + } + return true; + } + + public char charAt (int index) + { + if (index == 0) + { + return cached; + } + else if (index >= end) + { + return OUT_OF_BOUNDS; + } + else if (index == -1) + { + return lookBehind[0]; + } + else if (index == -2) + { + return lookBehind[1]; + } + else if (index < -2) + { + return OUT_OF_BOUNDS; + } + else if (index >= bufsize) + { + // Allocate more space in the buffer. + try + { + while (bufsize <= index) + bufsize += BUFFER_INCREMENT; + br.reset (); + br.mark (bufsize); + br.skip (index - 1); + } + catch (IOException e) + { + } + } + else if (this.index != index) + { + try + { + br.reset (); + br.skip (index - 1); + } + catch (IOException e) + { + } + } + char ch = OUT_OF_BOUNDS; + + try + { + int i = br.read (); + this.index = index + 1; // this.index is index of next pos relative to charAt(0) + if (i == -1) + { + // set flag that next should fail next time? + end = index; + return ch; + } + ch = (char) i; + } catch (IOException ie) + { + } + + return ch; + } + + public boolean move (int index) + { + // move read position [index] clicks from 'charAt(0)' + boolean retval = true; + while (retval && (index-- > 0)) + retval = next (); + return retval; + } + + public boolean isValid () + { + return (cached != OUT_OF_BOUNDS); + } + + public CharIndexed lookBehind (int index, int length) + { + throw new + UnsupportedOperationException + ("difficult to look behind for an input stream"); + } + + public int length () + { + throw new + UnsupportedOperationException + ("difficult to tell the length for an input stream"); + } + + public void setLastMatch (REMatch match) + { + throw new + UnsupportedOperationException + ("difficult to support setLastMatch for an input stream"); + } + + public REMatch getLastMatch () + { + throw new + UnsupportedOperationException + ("difficult to support getLastMatch for an input stream"); + } + + public void setHitEnd (REMatch match) + { + throw new + UnsupportedOperationException + ("difficult to support setHitEnd for an input stream"); + } + + public boolean hitEnd () + { + throw new + UnsupportedOperationException + ("difficult to support hitEnd for an input stream"); + } + + public int getAnchor () + { + throw new + UnsupportedOperationException + ("difficult to support getAnchor for an input stream"); + } + + public void setAnchor (int anchor) + { + throw new + UnsupportedOperationException + ("difficult to support setAnchor for an input stream"); + } + + public boolean move1 (int index) + { + throw new + UnsupportedOperationException + ("difficult to support move1 for an input stream"); + } + +} diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexedString.java b/libjava/classpath/gnu/java/util/regex/CharIndexedString.java new file mode 100644 index 000000000..7a56f487e --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/CharIndexedString.java @@ -0,0 +1,46 @@ +/* gnu/regexp/CharIndexedString.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.util.regex; + +class CharIndexedString extends CharIndexedCharSequence +{ + CharIndexedString (String str, int index) + { + super (str, index); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/CharIndexedStringBuffer.java b/libjava/classpath/gnu/java/util/regex/CharIndexedStringBuffer.java new file mode 100644 index 000000000..d6484f89b --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/CharIndexedStringBuffer.java @@ -0,0 +1,47 @@ +/* gnu/regexp/CharIndexedStringBuffer.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.util.regex; + +class CharIndexedStringBuffer extends CharIndexedCharSequence +{ + + CharIndexedStringBuffer (StringBuffer str, int index) + { + super (str, index); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/RE.java b/libjava/classpath/gnu/java/util/regex/RE.java new file mode 100644 index 000000000..5e9974a49 --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/RE.java @@ -0,0 +1,2675 @@ +/* gnu/regexp/RE.java + Copyright (C) 2006 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +import java.io.InputStream; +import java.io.Serializable; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.PropertyResourceBundle; +import java.util.ResourceBundle; + +/** + * RE provides the user interface for compiling and matching regular + * expressions. + *

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

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

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

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

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

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

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

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

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

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

    + * // Results:
    + * // m0.toString(): "food"
    + * // m1.toString(): "fool"
    + * // m2.toString(): null
    + * // m3.toString(): null
    + * // m4.toString(): "fool"
    + *
    + */ + public static final int REG_NOTBOL = 0x10; + + /** + * Execution flag. + * The match-end operator ($) does not match at the end + * of the input string. Useful for matching on substrings. + */ + public static final int REG_NOTEOL = 0x20; + + /** + * Execution flag. + * When a match method is invoked that starts matching at a non-zero + * index into the input, treat the input as if it begins at the index + * given. The effect of this flag is that the engine does not "see" + * any text in the input before the given index. This is useful so + * that the match-beginning operator (^) matches not at position 0 + * in the input string, but at the position the search started at + * (based on the index input given to the getMatch function). See + * the example under REG_NOTBOL. It also affects the use of the \< + * and \b operators. + */ + public static final int REG_ANCHORINDEX = 0x40; + + /** + * Execution flag. + * The substitute and substituteAll methods will not attempt to + * interpolate occurrences of $1-$9 in the replacement text with + * the corresponding subexpressions. For example, you may want to + * replace all matches of "one dollar" with "$1". + */ + public static final int REG_NO_INTERPOLATE = 0x80; + + /** + * Execution flag. + * Try to match the whole input string. An implicit match-end operator + * is added to this regexp. + */ + public static final int REG_TRY_ENTIRE_MATCH = 0x0100; + + /** + * Execution flag. + * The substitute and substituteAll methods will treat the + * character '\' in the replacement as an escape to a literal + * character. In this case "\n", "\$", "\\", "\x40" and "\012" + * will become "n", "$", "\", "x40" and "012" respectively. + * This flag has no effect if REG_NO_INTERPOLATE is set on. + */ + public static final int REG_REPLACE_USE_BACKSLASHESCAPE = 0x0200; + + /** + * Compilation flag. Allow whitespace and comments in pattern. + * This is equivalent to the "/x" operator in Perl. + */ + public static final int REG_X_COMMENTS = 0x0400; + + /** + * Compilation flag. If set, REG_ICASE is effective only for US-ASCII. + */ + public static final int REG_ICASE_USASCII = 0x0800; + + /** + * Execution flag. + * Do not move the position at which the search begins. If not set, + * the starting position will be moved until a match is found. + */ + public static final int REG_FIX_STARTING_POSITION = 0x1000; + + /** Returns a string representing the version of the gnu.regexp package. */ + public static final String version () + { + return VERSION; + } + + // Retrieves a message from the ResourceBundle + static final String getLocalizedMessage (String key) + { + if (messages == null) + messages = + PropertyResourceBundle.getBundle (bundle, Locale.getDefault ()); + return messages.getString (key); + } + + /** + * Constructs a regular expression pattern buffer without any compilation + * flags set, and using the default syntax (RESyntax.RE_SYNTAX_PERL5). + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer or char[]. Other input types will be converted to + * strings using the toString() method. + * @exception REException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public RE (Object pattern) throws REException + { + this (pattern, 0, RESyntax.RE_SYNTAX_PERL5, 0, 0); + } + + /** + * Constructs a regular expression pattern buffer using the specified + * compilation flags and the default syntax (RESyntax.RE_SYNTAX_PERL5). + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer, or char[]. Other input types will be converted to + * strings using the toString() method. + * @param cflags The logical OR of any combination of the compilation flags listed above. + * @exception REException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public RE (Object pattern, int cflags) throws REException + { + this (pattern, cflags, RESyntax.RE_SYNTAX_PERL5, 0, 0); + } + + /** + * Constructs a regular expression pattern buffer using the specified + * compilation flags and regular expression syntax. + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer, or char[]. Other input types will be converted to + * strings using the toString() method. + * @param cflags The logical OR of any combination of the compilation flags listed above. + * @param syntax The type of regular expression syntax to use. + * @exception REException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public RE (Object pattern, int cflags, RESyntax syntax) throws REException + { + this (pattern, cflags, syntax, 0, 0); + } + + // internal constructor used for alternation + private RE (REToken first, REToken last, int subs, int subIndex, + int minLength, int maxLength) + { + super (subIndex); + firstToken = first; + lastToken = last; + numSubs = subs; + minimumLength = minLength; + maximumLength = maxLength; + addToken (new RETokenEndSub (subIndex)); + } + + private RE (Object patternObj, int cflags, RESyntax syntax, int myIndex, + int nextSub) throws REException + { + super (myIndex); // Subexpression index of this token. + initialize (patternObj, cflags, syntax, myIndex, nextSub); + } + + // For use by subclasses + protected RE () + { + super (0); + } + + // The meat of construction + protected void initialize (Object patternObj, int cflags, RESyntax syntax, + int myIndex, int nextSub) throws REException + { + char[] pattern; + if (patternObj instanceof String) + { + pattern = ((String) patternObj).toCharArray (); + } + else if (patternObj instanceof char[]) + { + pattern = (char[]) patternObj; + } + else if (patternObj instanceof StringBuffer) + { + pattern = new char[((StringBuffer) patternObj).length ()]; + ((StringBuffer) patternObj).getChars (0, pattern.length, pattern, 0); + } + else if (patternObj instanceof StringBuilder) + { + pattern = new char[((StringBuilder) patternObj).length ()]; + ((StringBuilder) patternObj).getChars (0, pattern.length, pattern, 0); + } + else if (patternObj instanceof CPStringBuilder) + { + pattern = new char[((CPStringBuilder) patternObj).length ()]; + ((CPStringBuilder) patternObj).getChars (0, pattern.length, pattern, + 0); + } + else + { + pattern = patternObj.toString ().toCharArray (); + } + + int pLength = pattern.length; + + numSubs = 0; // Number of subexpressions in this token. + ArrayList < REToken > branches = null; + + // linked list of tokens (sort of -- some closed loops can exist) + firstToken = lastToken = null; + + // Precalculate these so we don't pay for the math every time we + // need to access them. + boolean insens = ((cflags & REG_ICASE) > 0); + boolean insensUSASCII = ((cflags & REG_ICASE_USASCII) > 0); + + // Parse pattern into tokens. Does anyone know if it's more efficient + // to use char[] than a String.charAt()? I'm assuming so. + + // index tracks the position in the char array + int index = 0; + + // this will be the current parse character (pattern[index]) + CharUnit unit = new CharUnit (); + + // This is used for {x,y} calculations + IntPair minMax = new IntPair (); + + // Buffer a token so we can create a TokenRepeated, etc. + REToken currentToken = null; + boolean quot = false; + + // Saved syntax and flags. + RESyntax savedSyntax = null; + int savedCflags = 0; + boolean flagsSaved = false; + + while (index < pLength) + { + // read the next character unit (including backslash escapes) + index = getCharUnit (pattern, index, unit, quot); + + if (unit.bk) + if (unit.ch == 'Q') + { + quot = true; + continue; + } + else if (unit.ch == 'E') + { + quot = false; + continue; + } + if (quot) + unit.bk = false; + + if (((cflags & REG_X_COMMENTS) > 0) && (!unit.bk) && (!quot)) + { + if (Character.isWhitespace (unit.ch)) + { + continue; + } + if (unit.ch == '#') + { + for (int i = index; i < pLength; i++) + { + if (pattern[i] == '\n') + { + index = i + 1; + continue; + } + else if (pattern[i] == '\r') + { + if (i + 1 < pLength && pattern[i + 1] == '\n') + { + index = i + 2; + } + else + { + index = i + 1; + } + continue; + } + } + index = pLength; + continue; + } + } + + // ALTERNATION OPERATOR + // \| or | (if RE_NO_BK_VBAR) or newline (if RE_NEWLINE_ALT) + // not available if RE_LIMITED_OPS is set + + // TODO: the '\n' literal here should be a test against REToken.newline, + // which unfortunately may be more than a single character. + if (((unit.ch == '|' + && (syntax.get (RESyntax.RE_NO_BK_VBAR) ^ (unit.bk || quot))) + || (syntax.get (RESyntax.RE_NEWLINE_ALT) && (unit.ch == '\n') + && !(unit.bk || quot))) + && !syntax.get (RESyntax.RE_LIMITED_OPS)) + { + // make everything up to here be a branch. create vector if nec. + addToken (currentToken); + RE theBranch = + new RE (firstToken, lastToken, numSubs, subIndex, minimumLength, + maximumLength); + minimumLength = 0; + maximumLength = 0; + if (branches == null) + { + branches = new ArrayList < REToken > (); + } + branches.add (theBranch); + firstToken = lastToken = currentToken = null; + } + + // INTERVAL OPERATOR: + // {x} | {x,} | {x,y} (RE_INTERVALS && RE_NO_BK_BRACES) + // \{x\} | \{x,\} | \{x,y\} (RE_INTERVALS && !RE_NO_BK_BRACES) + // + // OPEN QUESTION: + // what is proper interpretation of '{' at start of string? + // + // This method used to check "repeat.empty.token" to avoid such regexp + // as "(a*){2,}", but now "repeat.empty.token" is allowed. + + else if ((unit.ch == '{') && syntax.get (RESyntax.RE_INTERVALS) + && (syntax. + get (RESyntax.RE_NO_BK_BRACES) ^ (unit.bk || quot))) + { + int newIndex = getMinMax (pattern, index, minMax, syntax); + if (newIndex > index) + { + if (minMax.first > minMax.second) + throw new + REException (getLocalizedMessage ("interval.order"), + REException.REG_BADRPT, newIndex); + if (currentToken == null) + throw new + REException (getLocalizedMessage ("repeat.no.token"), + REException.REG_BADRPT, newIndex); + if (currentToken instanceof RETokenRepeated) + throw new + REException (getLocalizedMessage ("repeat.chained"), + REException.REG_BADRPT, newIndex); + if (currentToken instanceof RETokenWordBoundary + || currentToken instanceof RETokenWordBoundary) + throw new + REException (getLocalizedMessage ("repeat.assertion"), + REException.REG_BADRPT, newIndex); + index = newIndex; + currentToken = + setRepeated (currentToken, minMax.first, minMax.second, + index); + } + else + { + addToken (currentToken); + currentToken = new RETokenChar (subIndex, unit.ch, insens); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + } + + // LIST OPERATOR: + // [...] | [^...] + + else if ((unit.ch == '[') && !(unit.bk || quot)) + { + // Create a new RETokenOneOf + ParseCharClassResult result = + parseCharClass (subIndex, pattern, index, pLength, cflags, + syntax, 0); + addToken (currentToken); + currentToken = result.token; + index = result.index; + } + + // SUBEXPRESSIONS + // (...) | \(...\) depending on RE_NO_BK_PARENS + + else if ((unit.ch == '(') + && (syntax. + get (RESyntax.RE_NO_BK_PARENS) ^ (unit.bk || quot))) + { + boolean pure = false; + boolean comment = false; + boolean lookAhead = false; + boolean lookBehind = false; + boolean independent = false; + boolean negativelh = false; + boolean negativelb = false; + if ((index + 1 < pLength) && (pattern[index] == '?')) + { + switch (pattern[index + 1]) + { + case '!': + if (syntax.get (RESyntax.RE_LOOKAHEAD)) + { + pure = true; + negativelh = true; + lookAhead = true; + index += 2; + } + break; + case '=': + if (syntax.get (RESyntax.RE_LOOKAHEAD)) + { + pure = true; + lookAhead = true; + index += 2; + } + break; + case '<': + // We assume that if the syntax supports look-ahead, + // it also supports look-behind. + if (syntax.get (RESyntax.RE_LOOKAHEAD)) + { + index++; + switch (pattern[index + 1]) + { + case '!': + pure = true; + negativelb = true; + lookBehind = true; + index += 2; + break; + case '=': + pure = true; + lookBehind = true; + index += 2; + } + } + break; + case '>': + // We assume that if the syntax supports look-ahead, + // it also supports independent group. + if (syntax.get (RESyntax.RE_LOOKAHEAD)) + { + pure = true; + independent = true; + index += 2; + } + break; + case 'i': + case 'd': + case 'm': + case 's': + case 'u': + case 'x': + case '-': + if (!syntax.get (RESyntax.RE_EMBEDDED_FLAGS)) + break; + // Set or reset syntax flags. + int flagIndex = index + 1; + int endFlag = -1; + RESyntax newSyntax = new RESyntax (syntax); + int newCflags = cflags; + boolean negate = false; + while (flagIndex < pLength && endFlag < 0) + { + switch (pattern[flagIndex]) + { + case 'i': + if (negate) + newCflags &= ~REG_ICASE; + else + newCflags |= REG_ICASE; + flagIndex++; + break; + case 'd': + if (negate) + newSyntax.setLineSeparator (RESyntax. + DEFAULT_LINE_SEPARATOR); + else + newSyntax.setLineSeparator ("\n"); + flagIndex++; + break; + case 'm': + if (negate) + newCflags &= ~REG_MULTILINE; + else + newCflags |= REG_MULTILINE; + flagIndex++; + break; + case 's': + if (negate) + newCflags &= ~REG_DOT_NEWLINE; + else + newCflags |= REG_DOT_NEWLINE; + flagIndex++; + break; + case 'u': + if (negate) + newCflags |= REG_ICASE_USASCII; + else + newCflags &= ~REG_ICASE_USASCII; + flagIndex++; + break; + case 'x': + if (negate) + newCflags &= ~REG_X_COMMENTS; + else + newCflags |= REG_X_COMMENTS; + flagIndex++; + break; + case '-': + negate = true; + flagIndex++; + break; + case ':': + case ')': + endFlag = pattern[flagIndex]; + break; + default: + throw new + REException (getLocalizedMessage + ("repeat.no.token"), + REException.REG_BADRPT, index); + } + } + if (endFlag == ')') + { + syntax = newSyntax; + cflags = newCflags; + insens = ((cflags & REG_ICASE) > 0); + insensUSASCII = ((cflags & REG_ICASE_USASCII) > 0); + // This can be treated as though it were a comment. + comment = true; + index = flagIndex - 1; + break; + } + if (endFlag == ':') + { + savedSyntax = syntax; + savedCflags = cflags; + flagsSaved = true; + syntax = newSyntax; + cflags = newCflags; + insens = ((cflags & REG_ICASE) > 0); + insensUSASCII = ((cflags & REG_ICASE_USASCII) > 0); + index = flagIndex - 1; + // Fall through to the next case. + } + else + { + throw new + REException (getLocalizedMessage + ("unmatched.paren"), + REException.REG_ESUBREG, index); + } + case ':': + if (syntax.get (RESyntax.RE_PURE_GROUPING)) + { + pure = true; + index += 2; + } + break; + case '#': + if (syntax.get (RESyntax.RE_COMMENTS)) + { + comment = true; + } + break; + default: + throw new + REException (getLocalizedMessage ("repeat.no.token"), + REException.REG_BADRPT, index); + } + } + + if (index >= pLength) + { + throw new + REException (getLocalizedMessage ("unmatched.paren"), + REException.REG_ESUBREG, index); + } + + // find end of subexpression + int endIndex = index; + int nextIndex = index; + int nested = 0; + + while (((nextIndex = + getCharUnit (pattern, endIndex, unit, false)) > 0) + && !(nested == 0 && (unit.ch == ')') + && (syntax. + get (RESyntax.RE_NO_BK_PARENS) ^ (unit.bk + || quot)))) + { + if ((endIndex = nextIndex) >= pLength) + throw new + REException (getLocalizedMessage ("subexpr.no.end"), + REException.REG_ESUBREG, nextIndex); + else + if ((unit.ch == '[') && !(unit.bk || quot)) + { + // I hate to do something similar to the LIST OPERATOR matters + // above, but ... + int listIndex = nextIndex; + if (listIndex < pLength && pattern[listIndex] == '^') + listIndex++; + if (listIndex < pLength && pattern[listIndex] == ']') + listIndex++; + int listEndIndex = -1; + int listNest = 0; + while (listIndex < pLength && listEndIndex < 0) + { + switch (pattern[listIndex++]) + { + case '\\': + listIndex++; + break; + case '[': + // Sun's API document says that regexp like "[a-d[m-p]]" + // is legal. Even something like "[[[^]]]]" is accepted. + listNest++; + if (listIndex < pLength + && pattern[listIndex] == '^') + listIndex++; + if (listIndex < pLength + && pattern[listIndex] == ']') + listIndex++; + break; + case ']': + if (listNest == 0) + listEndIndex = listIndex; + listNest--; + break; + } + } + if (listEndIndex >= 0) + { + nextIndex = listEndIndex; + if ((endIndex = nextIndex) >= pLength) + throw new + REException (getLocalizedMessage ("subexpr.no.end"), + REException.REG_ESUBREG, nextIndex); + else + continue; + } + throw new + REException (getLocalizedMessage ("subexpr.no.end"), + REException.REG_ESUBREG, nextIndex); + } + else if (unit.ch == '(' + && (syntax. + get (RESyntax.RE_NO_BK_PARENS) ^ (unit.bk + || quot))) + nested++; + else if (unit.ch == ')' + && (syntax. + get (RESyntax.RE_NO_BK_PARENS) ^ (unit.bk + || quot))) + nested--; + } + + // endIndex is now position at a ')','\)' + // nextIndex is end of string or position after ')' or '\)' + + if (comment) + index = nextIndex; + else + { // not a comment + // create RE subexpression as token. + addToken (currentToken); + if (!pure) + { + numSubs++; + } + + int useIndex = (pure || lookAhead || lookBehind + || independent) ? 0 : nextSub + numSubs; + currentToken = + new RE (String.valueOf (pattern, index, endIndex - index). + toCharArray (), cflags, syntax, useIndex, + nextSub + numSubs); + numSubs += ((RE) currentToken).getNumSubs (); + + if (lookAhead) + { + currentToken = + new RETokenLookAhead (currentToken, negativelh); + } + else if (lookBehind) + { + currentToken = + new RETokenLookBehind (currentToken, negativelb); + } + else if (independent) + { + currentToken = new RETokenIndependent (currentToken); + } + + index = nextIndex; + if (flagsSaved) + { + syntax = savedSyntax; + cflags = savedCflags; + insens = ((cflags & REG_ICASE) > 0); + insensUSASCII = ((cflags & REG_ICASE_USASCII) > 0); + flagsSaved = false; + } + } // not a comment + } // subexpression + + // UNMATCHED RIGHT PAREN + // ) or \) throw exception if + // !syntax.get(RESyntax.RE_UNMATCHED_RIGHT_PAREN_ORD) + else if (!syntax.get (RESyntax.RE_UNMATCHED_RIGHT_PAREN_ORD) + && ((unit.ch == ')') + && (syntax. + get (RESyntax.RE_NO_BK_PARENS) ^ (unit.bk || quot)))) + { + throw new REException (getLocalizedMessage ("unmatched.paren"), + REException.REG_EPAREN, index); + } + + // START OF LINE OPERATOR + // ^ + + else if ((unit.ch == '^') && !(unit.bk || quot)) + { + addToken (currentToken); + currentToken = null; + RETokenStart token = null; + if ((cflags & REG_MULTILINE) > 0) + { + String sep = syntax.getLineSeparator (); + if (sep == null) + { + token = new RETokenStart (subIndex, null, true); + } + else + { + token = new RETokenStart (subIndex, sep); + } + } + else + { + token = new RETokenStart (subIndex, null); + } + addToken (token); + } + + // END OF LINE OPERATOR + // $ + + else if ((unit.ch == '$') && !(unit.bk || quot)) + { + addToken (currentToken); + currentToken = null; + RETokenEnd token = null; + if ((cflags & REG_MULTILINE) > 0) + { + String sep = syntax.getLineSeparator (); + if (sep == null) + { + token = new RETokenEnd (subIndex, null, true); + } + else + { + token = new RETokenEnd (subIndex, sep); + } + } + else + { + token = new RETokenEnd (subIndex, null); + } + addToken (token); + } + + // MATCH-ANY-CHARACTER OPERATOR (except possibly newline and null) + // . + + else if ((unit.ch == '.') && !(unit.bk || quot)) + { + addToken (currentToken); + currentToken = + new RETokenAny (subIndex, syntax.get (RESyntax.RE_DOT_NEWLINE) + || ((cflags & REG_DOT_NEWLINE) > 0), + syntax.get (RESyntax.RE_DOT_NOT_NULL)); + } + + // ZERO-OR-MORE REPEAT OPERATOR + // * + // + // This method used to check "repeat.empty.token" to avoid such regexp + // as "(a*)*", but now "repeat.empty.token" is allowed. + + else if ((unit.ch == '*') && !(unit.bk || quot)) + { + if (currentToken == null) + throw new REException (getLocalizedMessage ("repeat.no.token"), + REException.REG_BADRPT, index); + if (currentToken instanceof RETokenRepeated) + throw new REException (getLocalizedMessage ("repeat.chained"), + REException.REG_BADRPT, index); + if (currentToken instanceof RETokenWordBoundary + || currentToken instanceof RETokenWordBoundary) + throw new REException (getLocalizedMessage ("repeat.assertion"), + REException.REG_BADRPT, index); + currentToken = + setRepeated (currentToken, 0, Integer.MAX_VALUE, index); + } + + // ONE-OR-MORE REPEAT OPERATOR / POSSESSIVE MATCHING OPERATOR + // + | \+ depending on RE_BK_PLUS_QM + // not available if RE_LIMITED_OPS is set + // + // This method used to check "repeat.empty.token" to avoid such regexp + // as "(a*)+", but now "repeat.empty.token" is allowed. + + else if ((unit.ch == '+') && !syntax.get (RESyntax.RE_LIMITED_OPS) + && (!syntax. + get (RESyntax.RE_BK_PLUS_QM) ^ (unit.bk || quot))) + { + if (currentToken == null) + throw new REException (getLocalizedMessage ("repeat.no.token"), + REException.REG_BADRPT, index); + + // Check for possessive matching on RETokenRepeated + if (currentToken instanceof RETokenRepeated) + { + RETokenRepeated tokenRep = (RETokenRepeated) currentToken; + if (syntax.get (RESyntax.RE_POSSESSIVE_OPS) + && !tokenRep.isPossessive () && !tokenRep.isStingy ()) + tokenRep.makePossessive (); + else + throw new + REException (getLocalizedMessage ("repeat.chained"), + REException.REG_BADRPT, index); + + } + else if (currentToken instanceof RETokenWordBoundary + || currentToken instanceof RETokenWordBoundary) + throw new REException (getLocalizedMessage ("repeat.assertion"), + REException.REG_BADRPT, index); + else + currentToken = + setRepeated (currentToken, 1, Integer.MAX_VALUE, index); + } + + // ZERO-OR-ONE REPEAT OPERATOR / STINGY MATCHING OPERATOR + // ? | \? depending on RE_BK_PLUS_QM + // not available if RE_LIMITED_OPS is set + // stingy matching if RE_STINGY_OPS is set and it follows a quantifier + + else if ((unit.ch == '?') && !syntax.get (RESyntax.RE_LIMITED_OPS) + && (!syntax. + get (RESyntax.RE_BK_PLUS_QM) ^ (unit.bk || quot))) + { + if (currentToken == null) + throw new REException (getLocalizedMessage ("repeat.no.token"), + REException.REG_BADRPT, index); + + // Check for stingy matching on RETokenRepeated + if (currentToken instanceof RETokenRepeated) + { + RETokenRepeated tokenRep = (RETokenRepeated) currentToken; + if (syntax.get (RESyntax.RE_STINGY_OPS) + && !tokenRep.isStingy () && !tokenRep.isPossessive ()) + tokenRep.makeStingy (); + else + throw new + REException (getLocalizedMessage ("repeat.chained"), + REException.REG_BADRPT, index); + } + else if (currentToken instanceof RETokenWordBoundary + || currentToken instanceof RETokenWordBoundary) + throw new REException (getLocalizedMessage ("repeat.assertion"), + REException.REG_BADRPT, index); + else + currentToken = setRepeated (currentToken, 0, 1, index); + } + + // OCTAL CHARACTER + // \0377 + + else if (unit.bk && (unit.ch == '0') + && syntax.get (RESyntax.RE_OCTAL_CHAR)) + { + CharExpression ce = + getCharExpression (pattern, index - 2, pLength, syntax); + if (ce == null) + throw new REException ("invalid octal character", + REException.REG_ESCAPE, index); + index = index - 2 + ce.len; + addToken (currentToken); + currentToken = new RETokenChar (subIndex, ce.ch, insens); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // BACKREFERENCE OPERATOR + // \1 \2 ... \9 and \10 \11 \12 ... + // not available if RE_NO_BK_REFS is set + // Perl recognizes \10, \11, and so on only if enough number of + // parentheses have opened before it, otherwise they are treated + // as aliases of \010, \011, ... (octal characters). In case of + // Sun's JDK, octal character expression must always begin with \0. + // We will do as JDK does. But FIXME, take a look at "(a)(b)\29". + // JDK treats \2 as a back reference to the 2nd group because + // there are only two groups. But in our poor implementation, + // we cannot help but treat \29 as a back reference to the 29th group. + + else if (unit.bk && Character.isDigit (unit.ch) + && !syntax.get (RESyntax.RE_NO_BK_REFS)) + { + addToken (currentToken); + int numBegin = index - 1; + int numEnd = pLength; + for (int i = index; i < pLength; i++) + { + if (!Character.isDigit (pattern[i])) + { + numEnd = i; + break; + } + } + int num = parseInt (pattern, numBegin, numEnd - numBegin, 10); + + currentToken = new RETokenBackRef (subIndex, num, insens); + if (insensUSASCII) + currentToken.unicodeAware = false; + index = numEnd; + } + + // START OF STRING OPERATOR + // \A if RE_STRING_ANCHORS is set + + else if (unit.bk && (unit.ch == 'A') + && syntax.get (RESyntax.RE_STRING_ANCHORS)) + { + addToken (currentToken); + currentToken = new RETokenStart (subIndex, null); + } + + // WORD BREAK OPERATOR + // \b if ???? + + else if (unit.bk && (unit.ch == 'b') + && syntax.get (RESyntax.RE_STRING_ANCHORS)) + { + addToken (currentToken); + currentToken = + new RETokenWordBoundary (subIndex, + RETokenWordBoundary. + BEGIN | RETokenWordBoundary.END, + false); + } + + // WORD BEGIN OPERATOR + // \< if ???? + else if (unit.bk && (unit.ch == '<')) + { + addToken (currentToken); + currentToken = + new RETokenWordBoundary (subIndex, RETokenWordBoundary.BEGIN, + false); + } + + // WORD END OPERATOR + // \> if ???? + else if (unit.bk && (unit.ch == '>')) + { + addToken (currentToken); + currentToken = + new RETokenWordBoundary (subIndex, RETokenWordBoundary.END, + false); + } + + // NON-WORD BREAK OPERATOR + // \B if ???? + + else if (unit.bk && (unit.ch == 'B') + && syntax.get (RESyntax.RE_STRING_ANCHORS)) + { + addToken (currentToken); + currentToken = + new RETokenWordBoundary (subIndex, + RETokenWordBoundary. + BEGIN | RETokenWordBoundary.END, true); + } + + + // DIGIT OPERATOR + // \d if RE_CHAR_CLASS_ESCAPES is set + + else if (unit.bk && (unit.ch == 'd') + && syntax.get (RESyntax.RE_CHAR_CLASS_ESCAPES)) + { + addToken (currentToken); + currentToken = + new RETokenPOSIX (subIndex, RETokenPOSIX.DIGIT, insens, false); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // NON-DIGIT OPERATOR + // \D + + else if (unit.bk && (unit.ch == 'D') + && syntax.get (RESyntax.RE_CHAR_CLASS_ESCAPES)) + { + addToken (currentToken); + currentToken = + new RETokenPOSIX (subIndex, RETokenPOSIX.DIGIT, insens, true); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // NEWLINE ESCAPE + // \n + + else if (unit.bk && (unit.ch == 'n')) + { + addToken (currentToken); + currentToken = new RETokenChar (subIndex, '\n', false); + } + + // RETURN ESCAPE + // \r + + else if (unit.bk && (unit.ch == 'r')) + { + addToken (currentToken); + currentToken = new RETokenChar (subIndex, '\r', false); + } + + // WHITESPACE OPERATOR + // \s if RE_CHAR_CLASS_ESCAPES is set + + else if (unit.bk && (unit.ch == 's') + && syntax.get (RESyntax.RE_CHAR_CLASS_ESCAPES)) + { + addToken (currentToken); + currentToken = + new RETokenPOSIX (subIndex, RETokenPOSIX.SPACE, insens, false); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // NON-WHITESPACE OPERATOR + // \S + + else if (unit.bk && (unit.ch == 'S') + && syntax.get (RESyntax.RE_CHAR_CLASS_ESCAPES)) + { + addToken (currentToken); + currentToken = + new RETokenPOSIX (subIndex, RETokenPOSIX.SPACE, insens, true); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // TAB ESCAPE + // \t + + else if (unit.bk && (unit.ch == 't')) + { + addToken (currentToken); + currentToken = new RETokenChar (subIndex, '\t', false); + } + + // ALPHANUMERIC OPERATOR + // \w + + else if (unit.bk && (unit.ch == 'w') + && syntax.get (RESyntax.RE_CHAR_CLASS_ESCAPES)) + { + addToken (currentToken); + currentToken = + new RETokenPOSIX (subIndex, RETokenPOSIX.ALNUM, insens, false); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // NON-ALPHANUMERIC OPERATOR + // \W + + else if (unit.bk && (unit.ch == 'W') + && syntax.get (RESyntax.RE_CHAR_CLASS_ESCAPES)) + { + addToken (currentToken); + currentToken = + new RETokenPOSIX (subIndex, RETokenPOSIX.ALNUM, insens, true); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // END OF STRING OPERATOR + // \Z, \z + + // FIXME: \Z and \z are different in that if the input string + // ends with a line terminator, \Z matches the position before + // the final terminator. This special behavior of \Z is yet + // to be implemented. + + else if (unit.bk && (unit.ch == 'Z' || unit.ch == 'z') && + syntax.get (RESyntax.RE_STRING_ANCHORS)) + { + addToken (currentToken); + currentToken = new RETokenEnd (subIndex, null); + } + + // HEX CHARACTER, UNICODE CHARACTER + // \x1B, \u1234 + + else + if ((unit.bk && (unit.ch == 'x') + && syntax.get (RESyntax.RE_HEX_CHAR)) || (unit.bk + && (unit.ch == 'u') + && syntax. + get (RESyntax. + RE_UNICODE_CHAR))) + { + CharExpression ce = + getCharExpression (pattern, index - 2, pLength, syntax); + if (ce == null) + throw new REException ("invalid hex character", + REException.REG_ESCAPE, index); + index = index - 2 + ce.len; + addToken (currentToken); + currentToken = new RETokenChar (subIndex, ce.ch, insens); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // NAMED PROPERTY + // \p{prop}, \P{prop} + + else + if ((unit.bk && (unit.ch == 'p') + && syntax.get (RESyntax.RE_NAMED_PROPERTY)) || (unit.bk + && (unit.ch == + 'P') + && syntax. + get (RESyntax. + RE_NAMED_PROPERTY))) + { + NamedProperty np = getNamedProperty (pattern, index - 2, pLength); + if (np == null) + throw new REException ("invalid escape sequence", + REException.REG_ESCAPE, index); + index = index - 2 + np.len; + addToken (currentToken); + currentToken = + getRETokenNamedProperty (subIndex, np, insens, index); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + + // END OF PREVIOUS MATCH + // \G + + else if (unit.bk && (unit.ch == 'G') && + syntax.get (RESyntax.RE_STRING_ANCHORS)) + { + addToken (currentToken); + currentToken = new RETokenEndOfPreviousMatch (subIndex); + } + + // NON-SPECIAL CHARACTER (or escape to make literal) + // c | \* for example + + else + { // not a special character + addToken (currentToken); + currentToken = new RETokenChar (subIndex, unit.ch, insens); + if (insensUSASCII) + currentToken.unicodeAware = false; + } + } // end while + + // Add final buffered token and an EndSub marker + addToken (currentToken); + + if (branches != null) + { + branches. + add (new + RE (firstToken, lastToken, numSubs, subIndex, minimumLength, + maximumLength)); + branches.trimToSize (); // compact the Vector + minimumLength = 0; + maximumLength = 0; + firstToken = lastToken = null; + addToken (new RETokenOneOf (subIndex, branches, false)); + } + else + addToken (new RETokenEndSub (subIndex)); + + } + + private static class ParseCharClassResult + { + RETokenOneOf token; + int index; + boolean returnAtAndOperator = false; + } + + /** + * Parse [...] or [^...] and make an RETokenOneOf instance. + * @param subIndex subIndex to be given to the created RETokenOneOf instance. + * @param pattern Input array of characters to be parsed. + * @param index Index pointing to the character next to the beginning '['. + * @param pLength Limit of the input array. + * @param cflags Compilation flags used to parse the pattern. + * @param pflags Flags that affect the behavior of this method. + * @param syntax Syntax used to parse the pattern. + */ + private static ParseCharClassResult parseCharClass (int subIndex, + char[]pattern, + int index, int pLength, + int cflags, + RESyntax syntax, + int pflags) throws + REException + { + + boolean insens = ((cflags & REG_ICASE) > 0); + boolean insensUSASCII = ((cflags & REG_ICASE_USASCII) > 0); + final ArrayList < REToken > options = new ArrayList < REToken > (); + ArrayList < Object > addition = new ArrayList < Object > (); + boolean additionAndAppeared = false; + final int RETURN_AT_AND = 0x01; + boolean returnAtAndOperator = ((pflags & RETURN_AT_AND) != 0); + boolean negative = false; + char ch; + + char lastChar = 0; + boolean lastCharIsSet = false; + if (index == pLength) + throw new REException (getLocalizedMessage ("unmatched.bracket"), + REException.REG_EBRACK, index); + + // Check for initial caret, negation + if ((ch = pattern[index]) == '^') + { + negative = true; + if (++index == pLength) + throw new REException (getLocalizedMessage ("class.no.end"), + REException.REG_EBRACK, index); + ch = pattern[index]; + } + + // Check for leading right bracket literal + if (ch == ']') + { + lastChar = ch; + lastCharIsSet = true; + if (++index == pLength) + throw new REException (getLocalizedMessage ("class.no.end"), + REException.REG_EBRACK, index); + } + + while ((ch = pattern[index++]) != ']') + { + if ((ch == '-') && (lastCharIsSet)) + { + if (index == pLength) + throw new REException (getLocalizedMessage ("class.no.end"), + REException.REG_EBRACK, index); + if ((ch = pattern[index]) == ']') + { + RETokenChar t = new RETokenChar (subIndex, lastChar, insens); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + lastChar = '-'; + } + else + { + if ((ch == '\\') + && syntax.get (RESyntax.RE_BACKSLASH_ESCAPE_IN_LISTS)) + { + CharExpression ce = + getCharExpression (pattern, index, pLength, syntax); + if (ce == null) + throw new REException ("invalid escape sequence", + REException.REG_ESCAPE, index); + ch = ce.ch; + index = index + ce.len - 1; + } + RETokenRange t = + new RETokenRange (subIndex, lastChar, ch, insens); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + lastChar = 0; + lastCharIsSet = false; + index++; + } + } + else if ((ch == '\\') + && syntax.get (RESyntax.RE_BACKSLASH_ESCAPE_IN_LISTS)) + { + if (index == pLength) + throw new REException (getLocalizedMessage ("class.no.end"), + REException.REG_EBRACK, index); + int posixID = -1; + boolean negate = false; + char asciiEsc = 0; + boolean asciiEscIsSet = false; + NamedProperty np = null; + if (("dswDSW".indexOf (pattern[index]) != -1) + && syntax.get (RESyntax.RE_CHAR_CLASS_ESC_IN_LISTS)) + { + switch (pattern[index]) + { + case 'D': + negate = true; + case 'd': + posixID = RETokenPOSIX.DIGIT; + break; + case 'S': + negate = true; + case 's': + posixID = RETokenPOSIX.SPACE; + break; + case 'W': + negate = true; + case 'w': + posixID = RETokenPOSIX.ALNUM; + break; + } + } + if (("pP".indexOf (pattern[index]) != -1) + && syntax.get (RESyntax.RE_NAMED_PROPERTY)) + { + np = getNamedProperty (pattern, index - 1, pLength); + if (np == null) + throw new REException ("invalid escape sequence", + REException.REG_ESCAPE, index); + index = index - 1 + np.len - 1; + } + else + { + CharExpression ce = + getCharExpression (pattern, index - 1, pLength, syntax); + if (ce == null) + throw new REException ("invalid escape sequence", + REException.REG_ESCAPE, index); + asciiEsc = ce.ch; + asciiEscIsSet = true; + index = index - 1 + ce.len - 1; + } + if (lastCharIsSet) + { + RETokenChar t = new RETokenChar (subIndex, lastChar, insens); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + } + + if (posixID != -1) + { + RETokenPOSIX t = + new RETokenPOSIX (subIndex, posixID, insens, negate); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + } + else if (np != null) + { + RETokenNamedProperty t = + getRETokenNamedProperty (subIndex, np, insens, index); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + } + else if (asciiEscIsSet) + { + lastChar = asciiEsc; + lastCharIsSet = true; + } + else + { + lastChar = pattern[index]; + lastCharIsSet = true; + } + ++index; + } + else if ((ch == '[') && (syntax.get (RESyntax.RE_CHAR_CLASSES)) + && (index < pLength) && (pattern[index] == ':')) + { + CPStringBuilder posixSet = new CPStringBuilder (); + index = getPosixSet (pattern, index + 1, posixSet); + int posixId = RETokenPOSIX.intValue (posixSet.toString ()); + if (posixId != -1) + { + RETokenPOSIX t = + new RETokenPOSIX (subIndex, posixId, insens, false); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + } + } + else if ((ch == '[') && (syntax.get (RESyntax.RE_NESTED_CHARCLASS))) + { + ParseCharClassResult result = + parseCharClass (subIndex, pattern, index, pLength, cflags, + syntax, 0); + addition.add (result.token); + addition.add ("|"); + index = result.index; + } + else if ((ch == '&') && + (syntax.get (RESyntax.RE_NESTED_CHARCLASS)) && + (index < pLength) && (pattern[index] == '&')) + { + if (returnAtAndOperator) + { + ParseCharClassResult result = new ParseCharClassResult (); + options.trimToSize (); + if (additionAndAppeared) + addition.add ("&"); + if (addition.size () == 0) + addition = null; + result.token = new RETokenOneOf (subIndex, + options, addition, negative); + result.index = index - 1; + result.returnAtAndOperator = true; + return result; + } + // The precedence of the operator "&&" is the lowest. + // So we postpone adding "&" until other elements + // are added. And we insert Boolean.FALSE at the + // beginning of the list of tokens following "&&". + // So, "&&[a-b][k-m]" will be stored in the Vecter + // addition in this order: + // Boolean.FALSE, [a-b], "|", [k-m], "|", "&" + if (additionAndAppeared) + addition.add ("&"); + addition.add (Boolean.FALSE); + additionAndAppeared = true; + + // The part on which "&&" operates may be either + // (1) explicitly enclosed by [] + // or + // (2) not enclosed by [] and terminated by the + // next "&&" or the end of the character list. + // Let the preceding else if block do the case (1). + // We must do something in case of (2). + if ((index + 1 < pLength) && (pattern[index + 1] != '[')) + { + ParseCharClassResult result = + parseCharClass (subIndex, pattern, index + 1, pLength, + cflags, syntax, + RETURN_AT_AND); + addition.add (result.token); + addition.add ("|"); + // If the method returned at the next "&&", it is OK. + // Otherwise we have eaten the mark of the end of this + // character list "]". In this case we must give back + // the end mark. + index = (result.returnAtAndOperator ? + result.index : result.index - 1); + } + } + else + { + if (lastCharIsSet) + { + RETokenChar t = new RETokenChar (subIndex, lastChar, insens); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + } + lastChar = ch; + lastCharIsSet = true; + } + if (index == pLength) + throw new REException (getLocalizedMessage ("class.no.end"), + REException.REG_EBRACK, index); + } // while in list + // Out of list, index is one past ']' + + if (lastCharIsSet) + { + RETokenChar t = new RETokenChar (subIndex, lastChar, insens); + if (insensUSASCII) + t.unicodeAware = false; + options.add (t); + } + + ParseCharClassResult result = new ParseCharClassResult (); + // Create a new RETokenOneOf + options.trimToSize (); + if (additionAndAppeared) + addition.add ("&"); + if (addition.size () == 0) + addition = null; + result.token = new RETokenOneOf (subIndex, options, addition, negative); + result.index = index; + return result; + } + + private static int getCharUnit (char[]input, int index, CharUnit unit, + boolean quot) throws REException + { + unit.ch = input[index++]; + unit.bk = (unit.ch == '\\' + && (!quot || index >= input.length || input[index] == 'E')); + if (unit.bk) + if (index < input.length) + unit.ch = input[index++]; + else + throw new REException (getLocalizedMessage ("ends.with.backslash"), + REException.REG_ESCAPE, index); + return index; + } + + private static int parseInt (char[]input, int pos, int len, int radix) + { + int ret = 0; + for (int i = pos; i < pos + len; i++) + { + ret = ret * radix + Character.digit (input[i], radix); + } + return ret; + } + + /** + * This class represents various expressions for a character. + * "a" : 'a' itself. + * "\0123" : Octal char 0123 + * "\x1b" : Hex char 0x1b + * "\u1234" : Unicode char \u1234 + */ + private static class CharExpression + { + /** character represented by this expression */ + char ch; + /** String expression */ + String expr; + /** length of this expression */ + int len; + public String toString () + { + return expr; + } + } + + private static CharExpression getCharExpression (char[]input, int pos, + int lim, RESyntax syntax) + { + CharExpression ce = new CharExpression (); + char c = input[pos]; + if (c == '\\') + { + if (pos + 1 >= lim) + return null; + c = input[pos + 1]; + switch (c) + { + case 't': + ce.ch = '\t'; + ce.len = 2; + break; + case 'n': + ce.ch = '\n'; + ce.len = 2; + break; + case 'r': + ce.ch = '\r'; + ce.len = 2; + break; + case 'x': + case 'u': + if ((c == 'x' && syntax.get (RESyntax.RE_HEX_CHAR)) || + (c == 'u' && syntax.get (RESyntax.RE_UNICODE_CHAR))) + { + int l = 0; + int expectedLength = (c == 'x' ? 2 : 4); + for (int i = pos + 2; i < pos + 2 + expectedLength; i++) + { + if (i >= lim) + break; + if (!((input[i] >= '0' && input[i] <= '9') || + (input[i] >= 'A' && input[i] <= 'F') || + (input[i] >= 'a' && input[i] <= 'f'))) + break; + l++; + } + if (l != expectedLength) + return null; + ce.ch = (char) (parseInt (input, pos + 2, l, 16)); + ce.len = l + 2; + } + else + { + ce.ch = c; + ce.len = 2; + } + break; + case '0': + if (syntax.get (RESyntax.RE_OCTAL_CHAR)) + { + int l = 0; + for (int i = pos + 2; i < pos + 2 + 3; i++) + { + if (i >= lim) + break; + if (input[i] < '0' || input[i] > '7') + break; + l++; + } + if (l == 3 && input[pos + 2] > '3') + l--; + if (l <= 0) + return null; + ce.ch = (char) (parseInt (input, pos + 2, l, 8)); + ce.len = l + 2; + } + else + { + ce.ch = c; + ce.len = 2; + } + break; + default: + ce.ch = c; + ce.len = 2; + break; + } + } + else + { + ce.ch = input[pos]; + ce.len = 1; + } + ce.expr = new String (input, pos, ce.len); + return ce; + } + + /** + * This class represents a substring in a pattern string expressing + * a named property. + * "\pA" : Property named "A" + * "\p{prop}" : Property named "prop" + * "\PA" : Property named "A" (Negated) + * "\P{prop}" : Property named "prop" (Negated) + */ + private static class NamedProperty + { + /** Property name */ + String name; + /** Negated or not */ + boolean negate; + /** length of this expression */ + int len; + } + + private static NamedProperty getNamedProperty (char[]input, int pos, + int lim) + { + NamedProperty np = new NamedProperty (); + char c = input[pos]; + if (c == '\\') + { + if (++pos >= lim) + return null; + c = input[pos++]; + switch (c) + { + case 'p': + np.negate = false; + break; + case 'P': + np.negate = true; + break; + default: + return null; + } + c = input[pos++]; + if (c == '{') + { + int p = -1; + for (int i = pos; i < lim; i++) + { + if (input[i] == '}') + { + p = i; + break; + } + } + if (p < 0) + return null; + int len = p - pos; + np.name = new String (input, pos, len); + np.len = len + 4; + } + else + { + np.name = new String (input, pos - 1, 1); + np.len = 3; + } + return np; + } + else + return null; + } + + private static RETokenNamedProperty getRETokenNamedProperty (int subIndex, + NamedProperty + np, + boolean insens, + int index) + throws REException + { + try + { + return new RETokenNamedProperty (subIndex, np.name, insens, np.negate); + } + catch (REException e) + { + REException ree; + ree = new REException (e.getMessage (), REException.REG_ESCAPE, index); + ree.initCause (e); + throw ree; + } + } + + /** + * Checks if the regular expression matches the input in its entirety. + * + * @param input The input text. + */ + public boolean isMatch (Object input) + { + return isMatch (input, 0, 0); + } + + /** + * Checks if the input string, starting from index, is an exact match of + * this regular expression. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + */ + public boolean isMatch (Object input, int index) + { + return isMatch (input, index, 0); + } + + + /** + * Checks if the input, starting from index and using the specified + * execution flags, is an exact match of this regular expression. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + */ + public boolean isMatch (Object input, int index, int eflags) + { + return isMatchImpl (makeCharIndexed (input, index), index, eflags); + } + + private boolean isMatchImpl (CharIndexed input, int index, int eflags) + { + if (firstToken == null) // Trivial case + return (input.charAt (0) == CharIndexed.OUT_OF_BOUNDS); + REMatch m = new REMatch (numSubs, index, eflags); + if (firstToken.match (input, m)) + { + if (m != null) + { + if (input.charAt (m.index) == CharIndexed.OUT_OF_BOUNDS) + { + return true; + } + } + } + return false; + } + + /** + * Returns the maximum number of subexpressions in this regular expression. + * If the expression contains branches, the value returned will be the + * maximum subexpressions in any of the branches. + */ + public int getNumSubs () + { + return numSubs; + } + + // Overrides REToken.setUncle + void setUncle (REToken uncle) + { + if (lastToken != null) + { + lastToken.setUncle (uncle); + } + else + super.setUncle (uncle); // to deal with empty subexpressions + } + + // Overrides REToken.chain + + boolean chain (REToken next) + { + super.chain (next); + setUncle (next); + return true; + } + + /** + * Returns the minimum number of characters that could possibly + * constitute a match of this regular expression. + */ + public int getMinimumLength () + { + return minimumLength; + } + + public int getMaximumLength () + { + return maximumLength; + } + + /** + * Returns an array of all matches found in the input. + * + * If the regular expression allows the empty string to match, it will + * substitute matches at all positions except the end of the input. + * + * @param input The input text. + * @return a non-null (but possibly zero-length) array of matches + */ + public REMatch[] getAllMatches (Object input) + { + return getAllMatches (input, 0, 0); + } + + /** + * Returns an array of all matches found in the input, + * beginning at the specified index position. + * + * If the regular expression allows the empty string to match, it will + * substitute matches at all positions except the end of the input. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @return a non-null (but possibly zero-length) array of matches + */ + public REMatch[] getAllMatches (Object input, int index) + { + return getAllMatches (input, index, 0); + } + + /** + * Returns an array of all matches found in the input string, + * beginning at the specified index position and using the specified + * execution flags. + * + * If the regular expression allows the empty string to match, it will + * substitute matches at all positions except the end of the input. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return a non-null (but possibly zero-length) array of matches + */ + public REMatch[] getAllMatches (Object input, int index, int eflags) + { + return getAllMatchesImpl (makeCharIndexed (input, index), index, eflags); + } + + // this has been changed since 1.03 to be non-overlapping matches + private REMatch[] getAllMatchesImpl (CharIndexed input, int index, + int eflags) + { + List < REMatch > all = new ArrayList < REMatch > (); + REMatch m = null; + while ((m = getMatchImpl (input, index, eflags, null)) != null) + { + all.add (m); + index = m.getEndIndex (); + if (m.end[0] == 0) + { // handle pathological case of zero-length match + index++; + input.move (1); + } + else + { + input.move (m.end[0]); + } + if (!input.isValid ()) + break; + } + return all.toArray (new REMatch[all.size ()]); + } + + /* Implements abstract method REToken.match() */ + boolean match (CharIndexed input, REMatch mymatch) + { + input.setHitEnd (mymatch); + if (firstToken == null) + { + return next (input, mymatch); + } + + // Note the start of this subexpression + mymatch.start1[subIndex] = mymatch.index; + + return firstToken.match (input, mymatch); + } + + REMatch findMatch (CharIndexed input, REMatch mymatch) + { + if (mymatch.backtrackStack == null) + mymatch.backtrackStack = new BacktrackStack (); + boolean b = match (input, mymatch); + if (b) + { + return mymatch; + } + return null; + } + + /** + * Returns the first match found in the input. If no match is found, + * null is returned. + * + * @param input The input text. + * @return An REMatch instance referencing the match, or null if none. + */ + public REMatch getMatch (Object input) + { + return getMatch (input, 0, 0); + } + + /** + * Returns the first match found in the input, beginning + * the search at the specified index. If no match is found, + * returns null. + * + * @param input The input text. + * @param index The offset within the text to begin looking for a match. + * @return An REMatch instance referencing the match, or null if none. + */ + public REMatch getMatch (Object input, int index) + { + return getMatch (input, index, 0); + } + + /** + * Returns the first match found in the input, beginning + * the search at the specified index, and using the specified + * execution flags. If no match is found, returns null. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return An REMatch instance referencing the match, or null if none. + */ + public REMatch getMatch (Object input, int index, int eflags) + { + return getMatch (input, index, eflags, null); + } + + /** + * Returns the first match found in the input, beginning the search + * at the specified index, and using the specified execution flags. + * If no match is found, returns null. If a StringBuffer is + * provided and is non-null, the contents of the input text from the + * index to the beginning of the match (or to the end of the input, + * if there is no match) are appended to the StringBuffer. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @param buffer The StringBuffer to save pre-match text in. + * @return An REMatch instance referencing the match, or null if none. */ + public REMatch getMatch (Object input, int index, int eflags, + CPStringBuilder buffer) + { + return getMatchImpl (makeCharIndexed (input, index), index, eflags, + buffer); + } + + REMatch getMatchImpl (CharIndexed input, int anchor, int eflags, + CPStringBuilder buffer) + { + boolean tryEntireMatch = ((eflags & REG_TRY_ENTIRE_MATCH) != 0); + boolean doMove = ((eflags & REG_FIX_STARTING_POSITION) == 0); + RE re = (tryEntireMatch ? (RE) this.clone () : this); + if (tryEntireMatch) + { + RETokenEnd reEnd = new RETokenEnd (0, null); + reEnd.setFake (true); + re.chain (reEnd); + } + // Create a new REMatch to hold results + REMatch mymatch = new REMatch (numSubs, anchor, eflags); + do + { + /* The following potimization is commented out because + the matching should be tried even if the length of + input is obviously too short in order that + java.util.regex.Matcher#hitEnd() may work correctly. + // Optimization: check if anchor + minimumLength > length + if (minimumLength == 0 || input.charAt(minimumLength-1) != CharIndexed.OUT_OF_BOUNDS) { + */ + if (re.match (input, mymatch)) + { + REMatch best = mymatch; + // We assume that the match that coms first is the best. + // And the following "The longer, the better" rule has + // been commented out. The longest is not neccesarily + // the best. For example, "a" out of "aaa" is the best + // match for /a+?/. + /* + // Find best match of them all to observe leftmost longest + while ((mymatch = mymatch.next) != null) { + if (mymatch.index > best.index) { + best = mymatch; + } + } + */ + best.end[0] = best.index; + best.finish (input); + input.setLastMatch (best); + return best; + } + /* End of the optimization commented out + } + */ + mymatch.clear (++anchor); + // Append character to buffer if needed + if (buffer != null && input.charAt (0) != CharIndexed.OUT_OF_BOUNDS) + { + buffer.append (input.charAt (0)); + } + // java.util.regex.Matcher#hitEnd() requires that the search should + // be tried at the end of input, so we use move1(1) instead of move(1) + } + while (doMove && input.move1 (1)); + + // Special handling at end of input for e.g. "$" + if (minimumLength == 0) + { + if (match (input, mymatch)) + { + mymatch.finish (input); + return mymatch; + } + } + + return null; + } + + /** + * Returns an REMatchEnumeration that can be used to iterate over the + * matches found in the input text. + * + * @param input The input text. + * @return A non-null REMatchEnumeration instance. + */ + public REMatchEnumeration getMatchEnumeration (Object input) + { + return getMatchEnumeration (input, 0, 0); + } + + + /** + * Returns an REMatchEnumeration that can be used to iterate over the + * matches found in the input text. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @return A non-null REMatchEnumeration instance, with its input cursor + * set to the index position specified. + */ + public REMatchEnumeration getMatchEnumeration (Object input, int index) + { + return getMatchEnumeration (input, index, 0); + } + + /** + * Returns an REMatchEnumeration that can be used to iterate over the + * matches found in the input text. + * + * @param input The input text. + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return A non-null REMatchEnumeration instance, with its input cursor + * set to the index position specified. + */ + public REMatchEnumeration getMatchEnumeration (Object input, int index, + int eflags) + { + return new REMatchEnumeration (this, makeCharIndexed (input, index), + index, eflags); + } + + + /** + * Substitutes the replacement text for the first match found in the input. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @return A String interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substitute (Object input, String replace) + { + return substitute (input, replace, 0, 0); + } + + /** + * Substitutes the replacement text for the first match found in the input + * beginning at the specified index position. Specifying an index + * effectively causes the regular expression engine to throw away the + * specified number of characters. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @param index The offset index at which the search should be begin. + * @return A String containing the substring of the input, starting + * at the index position, and interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substitute (Object input, String replace, int index) + { + return substitute (input, replace, index, 0); + } + + /** + * Substitutes the replacement text for the first match found in the input + * string, beginning at the specified index position and using the + * specified execution flags. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return A String containing the substring of the input, starting + * at the index position, and interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substitute (Object input, String replace, int index, + int eflags) + { + return substituteImpl (makeCharIndexed (input, index), replace, index, + eflags); + } + + private String substituteImpl (CharIndexed input, String replace, int index, + int eflags) + { + CPStringBuilder buffer = new CPStringBuilder (); + REMatch m = getMatchImpl (input, index, eflags, buffer); + if (m == null) + return buffer.toString (); + buffer.append (getReplacement (replace, m, eflags)); + if (input.move (m.end[0])) + { + do + { + buffer.append (input.charAt (0)); + } + while (input.move (1)); + } + return buffer.toString (); + } + + /** + * Substitutes the replacement text for each non-overlapping match found + * in the input text. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @return A String interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substituteAll (Object input, String replace) + { + return substituteAll (input, replace, 0, 0); + } + + /** + * Substitutes the replacement text for each non-overlapping match found + * in the input text, starting at the specified index. + * + * If the regular expression allows the empty string to match, it will + * substitute matches at all positions except the end of the input. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @param index The offset index at which the search should be begin. + * @return A String containing the substring of the input, starting + * at the index position, and interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substituteAll (Object input, String replace, int index) + { + return substituteAll (input, replace, index, 0); + } + + /** + * Substitutes the replacement text for each non-overlapping match found + * in the input text, starting at the specified index and using the + * specified execution flags. + * + * @param input The input text. + * @param replace The replacement text, which may contain $x metacharacters (see REMatch.substituteInto). + * @param index The offset index at which the search should be begin. + * @param eflags The logical OR of any execution flags above. + * @return A String containing the substring of the input, starting + * at the index position, and interpolating the substituted text. + * @see REMatch#substituteInto + */ + public String substituteAll (Object input, String replace, int index, + int eflags) + { + return substituteAllImpl (makeCharIndexed (input, index), replace, index, + eflags); + } + + private String substituteAllImpl (CharIndexed input, String replace, + int index, int eflags) + { + CPStringBuilder buffer = new CPStringBuilder (); + REMatch m; + while ((m = getMatchImpl (input, index, eflags, buffer)) != null) + { + buffer.append (getReplacement (replace, m, eflags)); + index = m.getEndIndex (); + if (m.end[0] == 0) + { + char ch = input.charAt (0); + if (ch != CharIndexed.OUT_OF_BOUNDS) + buffer.append (ch); + input.move (1); + } + else + { + input.move (m.end[0]); + } + + if (!input.isValid ()) + break; + } + return buffer.toString (); + } + + public static String getReplacement (String replace, REMatch m, int eflags) + { + if ((eflags & REG_NO_INTERPOLATE) > 0) + return replace; + else + { + if ((eflags & REG_REPLACE_USE_BACKSLASHESCAPE) > 0) + { + CPStringBuilder sb = new CPStringBuilder (); + int l = replace.length (); + for (int i = 0; i < l; i++) + { + char c = replace.charAt (i); + switch (c) + { + case '\\': + i++; + // Let StringIndexOutOfBoundsException be thrown. + sb.append (replace.charAt (i)); + break; + case '$': + int i1 = i + 1; + while (i1 < replace.length () && + Character.isDigit (replace.charAt (i1))) + i1++; + sb.append (m.substituteInto (replace.substring (i, i1))); + i = i1 - 1; + break; + default: + sb.append (c); + } + } + return sb.toString (); + } + else + return m.substituteInto (replace); + } + } + + /* Helper function for constructor */ + private void addToken (REToken next) + { + if (next == null) + return; + minimumLength += next.getMinimumLength (); + int nmax = next.getMaximumLength (); + if (nmax < Integer.MAX_VALUE && maximumLength < Integer.MAX_VALUE) + maximumLength += nmax; + else + maximumLength = Integer.MAX_VALUE; + + if (firstToken == null) + { + lastToken = firstToken = next; + } + else + { + // if chain returns false, it "rejected" the token due to + // an optimization, and next was combined with lastToken + if (lastToken.chain (next)) + { + lastToken = next; + } + } + } + + private static REToken setRepeated (REToken current, int min, int max, + int index) throws REException + { + if (current == null) + throw new REException (getLocalizedMessage ("repeat.no.token"), + REException.REG_BADRPT, index); + return new RETokenRepeated (current.subIndex, current, min, max); + } + + private static int getPosixSet (char[]pattern, int index, + CPStringBuilder buf) + { + // Precondition: pattern[index-1] == ':' + // we will return pos of closing ']'. + int i; + for (i = index; i < (pattern.length - 1); i++) + { + if ((pattern[i] == ':') && (pattern[i + 1] == ']')) + return i + 2; + buf.append (pattern[i]); + } + return index; // didn't match up + } + + private int getMinMax (char[]input, int index, IntPair minMax, + RESyntax syntax) throws REException + { + // Precondition: input[index-1] == '{', minMax != null + + boolean mustMatch = !syntax.get (RESyntax.RE_NO_BK_BRACES); + int startIndex = index; + if (index == input.length) + { + if (mustMatch) + throw new REException (getLocalizedMessage ("unmatched.brace"), + REException.REG_EBRACE, index); + else + return startIndex; + } + + int min, max = 0; + CharUnit unit = new CharUnit (); + CPStringBuilder buf = new CPStringBuilder (); + + // Read string of digits + do + { + index = getCharUnit (input, index, unit, false); + if (Character.isDigit (unit.ch)) + buf.append (unit.ch); + } + while ((index != input.length) && Character.isDigit (unit.ch)); + + // Check for {} tomfoolery + if (buf.length () == 0) + { + if (mustMatch) + throw new REException (getLocalizedMessage ("interval.error"), + REException.REG_EBRACE, index); + else + return startIndex; + } + + min = Integer.parseInt (buf.toString ()); + + if ((unit.ch == '}') && (syntax.get (RESyntax.RE_NO_BK_BRACES) ^ unit.bk)) + max = min; + else if (index == input.length) + if (mustMatch) + throw new REException (getLocalizedMessage ("interval.no.end"), + REException.REG_EBRACE, index); + else + return startIndex; + else + if ((unit.ch == ',') && !unit.bk) + { + buf = new CPStringBuilder (); + // Read string of digits + while (((index = + getCharUnit (input, index, unit, false)) != input.length) + && Character.isDigit (unit.ch)) + buf.append (unit.ch); + + if (! + ((unit.ch == '}') + && (syntax.get (RESyntax.RE_NO_BK_BRACES) ^ unit.bk))) + if (mustMatch) + throw new REException (getLocalizedMessage ("interval.error"), + REException.REG_EBRACE, index); + else + return startIndex; + + // This is the case of {x,} + if (buf.length () == 0) + max = Integer.MAX_VALUE; + else + max = Integer.parseInt (buf.toString ()); + } + else if (mustMatch) + throw new REException (getLocalizedMessage ("interval.error"), + REException.REG_EBRACE, index); + else + return startIndex; + + // We know min and max now, and they are valid. + + minMax.first = min; + minMax.second = max; + + // return the index following the '}' + return index; + } + + /** + * Return a human readable form of the compiled regular expression, + * useful for debugging. + */ + public String toString () + { + CPStringBuilder sb = new CPStringBuilder (); + dump (sb); + return sb.toString (); + } + + void dump (CPStringBuilder os) + { + os.append ("(?#startRE subIndex=" + subIndex + ")"); + if (subIndex == 0) + os.append ("?:"); + if (firstToken != null) + firstToken.dumpAll (os); + if (subIndex == 0) + os.append (")"); + os.append ("(?#endRE subIndex=" + subIndex + ")"); + } + + // Cast input appropriately or throw exception + // This method was originally a private method, but has been made + // public because java.util.regex.Matcher uses this. + public static CharIndexed makeCharIndexed (Object input, int index) + { + // The case where input is already a CharIndexed is supposed + // be the most likely because this is the case with + // java.util.regex.Matcher. + // We could let a String or a CharSequence fall through + // to final input, but since it'a very likely input type, + // we check it first. + if (input instanceof CharIndexed) + { + CharIndexed ci = (CharIndexed) input; + ci.setAnchor (index); + return ci; + } + else if (input instanceof CharSequence) + return new CharIndexedCharSequence ((CharSequence) input, index); + else if (input instanceof String) + return new CharIndexedString ((String) input, index); + else if (input instanceof char[]) + return new CharIndexedCharArray ((char[]) input, index); + else if (input instanceof StringBuffer) + return new CharIndexedStringBuffer ((StringBuffer) input, index); + else if (input instanceof InputStream) + return new CharIndexedInputStream ((InputStream) input, index); + else + return new CharIndexedString (input.toString (), index); + } +} diff --git a/libjava/classpath/gnu/java/util/regex/REException.java b/libjava/classpath/gnu/java/util/regex/REException.java new file mode 100644 index 000000000..5681ceeea --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/REException.java @@ -0,0 +1,198 @@ +/* gnu/regexp/REException.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +import java.text.MessageFormat; + +/** + * This is the regular expression exception class. An exception of this type + * defines the three attributes: + *

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

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

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

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

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

    + * But you can save yourself that work, since the toString() + * method (above) does exactly that for you. + */ + public int getEndIndex () + { + return offset + end[0]; + } + + /** + * Returns the string matching the given subexpression. The subexpressions + * are indexed starting with one, not zero. That is, the subexpression + * identified by the first set of parentheses in a regular expression + * could be retrieved from an REMatch by calling match.toString(1). + * + * @param sub Index of the subexpression. + */ + public String toString (int sub) + { + if ((sub >= start.length) || sub < 0) + throw new IndexOutOfBoundsException ("No group " + sub); + if (start[sub] == -1) + return null; + if (start[sub] >= 0 && end[sub] <= matchedText.length ()) + return (matchedText.substring (start[sub], end[sub])); + else + { + // This case occurs with RETokenLookAhead or RETokenLookBehind. + CPStringBuilder sb = new CPStringBuilder (); + int s = start[sub]; + int e = end[sub]; + if (s < 0) + s += 1; + if (e < 0) + e += 1; + for (int i = start[0] + s; i < start[0] + e; i++) + sb.append (matchedCharIndexed.charAt (i)); + return sb.toString (); + } + } + + /** + * Returns the index within the input string used to generate this match + * where subexpression number sub begins, or -1 if + * the subexpression does not exist. The initial position is zero. + * + * @param sub Subexpression index + * @deprecated Use getStartIndex(int) instead. + */ + public int getSubStartIndex (int sub) + { + if (sub >= start.length) + return -1; + int x = start[sub]; + return (x == -1) ? x : (x >= 0) ? offset + x : offset + x + 1; + } + + /** + * Returns the index within the input string used to generate this match + * where subexpression number sub begins, or -1 if + * the subexpression does not exist. The initial position is zero. + * + * @param sub Subexpression index + * @since gnu.regexp 1.1.0 + */ + public int getStartIndex (int sub) + { + if (sub >= start.length) + return -1; + int x = start[sub]; + return (x == -1) ? x : (x >= 0) ? offset + x : offset + x + 1; + } + + /** + * Returns the index within the input string used to generate this match + * where subexpression number sub ends, or -1 if + * the subexpression does not exist. The initial position is zero. + * + * @param sub Subexpression index + * @deprecated Use getEndIndex(int) instead + */ + public int getSubEndIndex (int sub) + { + if (sub >= start.length) + return -1; + int x = end[sub]; + return (x == -1) ? x : (x >= 0) ? offset + x : offset + x + 1; + } + + /** + * Returns the index within the input string used to generate this match + * where subexpression number sub ends, or -1 if + * the subexpression does not exist. The initial position is zero. + * + * @param sub Subexpression index + */ + public int getEndIndex (int sub) + { + if (sub >= start.length) + return -1; + int x = end[sub]; + return (x == -1) ? x : (x >= 0) ? offset + x : offset + x + 1; + } + + /** + * Substitute the results of this match to create a new string. + * This is patterned after PERL, so the tokens to watch out for are + * $0 through $9. $0 matches + * the full substring matched; $n matches + * subexpression number n. + * $10, $11, ... may match the 10th, 11th, ... subexpressions + * if such subexpressions exist. + * + * @param input A string consisting of literals and $n tokens. + */ + public String substituteInto (String input) + { + // a la Perl, $0 is whole thing, $1 - $9 are subexpressions + CPStringBuilder output = new CPStringBuilder (); + int pos; + for (pos = 0; pos < input.length () - 1; pos++) + { + if ((input.charAt (pos) == '$') + && (Character.isDigit (input.charAt (pos + 1)))) + { + int val = Character.digit (input.charAt (++pos), 10); + int pos1 = pos + 1; + while (pos1 < input.length () && + Character.isDigit (input.charAt (pos1))) + { + int val1 = + val * 10 + Character.digit (input.charAt (pos1), 10); + if (val1 >= start.length) + break; + pos1++; + val = val1; + } + pos = pos1 - 1; + + if (val < start.length) + { + output.append (toString (val)); + } + } + else + output.append (input.charAt (pos)); + } + if (pos < input.length ()) + output.append (input.charAt (pos)); + return output.toString (); + } + +/* The following are used for debugging purpose + public static String d(REMatch m) { + if (m == null) return "null"; + else return "[" + m.index + "]"; + } + + public String substringUptoIndex(CharIndexed input) { + StringBuffer sb = new StringBuffer(); + for (int i = 0; i < index; i++) { + sb.append(input.charAt(i)); + } + return sb.toString(); + } +*/ + +} diff --git a/libjava/classpath/gnu/java/util/regex/REMatchEnumeration.java b/libjava/classpath/gnu/java/util/regex/REMatchEnumeration.java new file mode 100644 index 000000000..04432d07c --- /dev/null +++ b/libjava/classpath/gnu/java/util/regex/REMatchEnumeration.java @@ -0,0 +1,141 @@ +/* gnu/regexp/REMatchEnumeration.java + Copyright (C) 1998-2001, 2004 Free Software Foundation, Inc. + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package gnu.java.util.regex; + +import gnu.java.lang.CPStringBuilder; + +import java.io.Serializable; +import java.util.Enumeration; +import java.util.NoSuchElementException; + +/** + * An REMatchEnumeration enumerates regular expression matches over a + * given input text. You obtain a reference to an enumeration using + * the getMatchEnumeration() methods on an instance of + * RE. + * + *

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

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

    + * Note that this makes UncheckedRE dangerous if constructed with + * dynamic data. Do not use UncheckedRE unless you are completely sure + * that all input being passed to it contains valid, well-formed + * regular expressions for the syntax specified. + * + * @author Wes Biggs + * @see gnu.java.util.regex.RE + * @since gnu.regexp 1.1.4 + */ + +public final class UncheckedRE extends RE +{ + /** + * Constructs a regular expression pattern buffer without any compilation + * flags set, and using the default syntax (RESyntax.RE_SYNTAX_PERL5). + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer or char[]. Other input types will be converted to + * strings using the toString() method. + * @exception RuntimeException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public UncheckedRE (Object pattern) + { + this (pattern, 0, RESyntax.RE_SYNTAX_PERL5); + } + + /** + * Constructs a regular expression pattern buffer using the specified + * compilation flags and the default syntax (RESyntax.RE_SYNTAX_PERL5). + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer, or char[]. Other input types will be converted to + * strings using the toString() method. + * @param cflags The logical OR of any combination of the compilation flags in the RE class. + * @exception RuntimeException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public UncheckedRE (Object pattern, int cflags) + { + this (pattern, cflags, RESyntax.RE_SYNTAX_PERL5); + } + + /** + * Constructs a regular expression pattern buffer using the specified + * compilation flags and regular expression syntax. + * + * @param pattern A regular expression pattern, in the form of a String, + * StringBuffer, or char[]. Other input types will be converted to + * strings using the toString() method. + * @param cflags The logical OR of any combination of the compilation flags in the RE class. + * @param syntax The type of regular expression syntax to use. + * @exception RuntimeException The input pattern could not be parsed. + * @exception NullPointerException The pattern was null. + */ + public UncheckedRE (Object pattern, int cflags, RESyntax syntax) + { + try + { + initialize (pattern, cflags, syntax, 0, 0); + } + catch (REException e) + { + throw new RuntimeException (e.getMessage ()); + } + } +} -- cgit v1.2.3